View Full Version : Low Level Graphics Programming Project
SynApsus
August 31st, 2004, 06:09
Hello.
I'm new in driver coding, I have yet some useful ( or not ) drivers written. But now i'm faced with a problem for which I don't have the answer.
I want to display a colored and formatted text on the screen using my driver, a text who will be displayed OVER all the other windows, even Fullscreen ones.
If someone could help me, by telling me what Native Apis can do that, for example... or just a link to a sourcecode or a compiled driver ( NT/2k/XP of course ) which I will be able to analyse.
[EDIT JMI: As this Thread progressed it was suggested that a collaberative effort might be made to accomplish some of the things discussed here and I suggested it might make a good Mini-Project. At the parties request, I have moved it here, in the hope those interested and qualified might contribute to that effort.]
bilbo
August 31st, 2004, 07:21
Are you searching for an OSD (On Screen Display)?
Look at http://www.codeproject.com/w2k/forecast.asp
Regards, bilbo
disavowed
August 31st, 2004, 07:30
SynApsus, siwvid.sys does what you want (when it's used to display softice in a popup window, as opposed to fullscreen)
nikolatesla20
August 31st, 2004, 08:01
I think you need to write a video mini-driver. A mini-driver plugs into the larger driver architecture of windows and allows you to do such specialized tasks as video. Most video drivers and sound card drivers are mini-class drivers. If you have the DDK, then you should be looking in the class drivers sections. It's a very steep learning curve so get out some coffee and have fun!
-nt20
Silver
August 31st, 2004, 08:49
The only GDI/Windows graphics book you will ever need:
Windows Graphics Programming Win32 GDI and DirectDraw®
Feng Yuan
Publisher: Prentice Hall PTR
ISBN: 0-13-086985-6
And it's floating around in .chm format too.
SynApsus
August 31st, 2004, 16:13
Thanks to all, especially for this excellent book which talks about Ring3 AND Ring0 graphical programming.
bilbo, I tried before to do this with a topmost window in ring3 level... it is not convenient for me. It is a timer window ( injected in a process ) whose text is modified every second, and if the process who displays this text is resource-greedy, the seconds do not ravel as normal ( every real second, they come too late )
More, if this text is displayed in a process who is in fullscreen mode, the fullscreen is disabled to display my text. I want she stays and the text to be displayed REALLY at the top. So, Ring0
If you have other links or other help to give, that would be very cool : the book is very interesting but not very complete about ring0 graphic programming. It just talks a little about it.
Excuse me for my english, I try to do as better as I can.
bilbo
September 3rd, 2004, 09:15
Well, in that case disavowed is right... siwvid.sys has complete control of the current screen, because it knows the current pixel format and the current address at which the video memory is mapped.
How it obtains this info? It reads from the registry a list of the video drivers used by the system (kernel DLLs), and hooks their entry point, which is DrvEnableDriver(), using a powerful hooking engine.
In this way it obtains a pointer to the driver structure DRVENABLEDATA, and it can hooks all the interface functions exported by the driver.
Regards, bilbo
user
September 18th, 2004, 10:24
Quote:
[Originally Posted by disavowed]SynApsus, siwvid.sys does what you want (when it's used to display softice in a popup window, as opposed to fullscreen) |
it's the exact opposite, ddraw knowledge is inside ntice itself, siwvid is the legacy video mode switching stuff.
homersux
September 27th, 2004, 16:51
I am interested in this aspect of graphics programming. Mainly how do you float a window inside a full screen mode game. This is probably doable with directx if the game itself uses directx engine. Could someone point me to some examples, pointers or tuts?
thx!
Silver
September 28th, 2004, 12:54
Homer, can you phrase your question a bit differently? "float a window"? You can make dialogs etc appear within a DX fullscreen app, but it's kludgy. The best way to make it appear as though a normal window is visible over a DX full screen app is to draw the window through the GDI normally, then blit it to a DX surface and use the surface as a texturemap for an RHW quad. I code a lot of DX/D3D stuff...
homersux
October 3rd, 2004, 13:56
Silver, something like an in game maphack is the kind of stuff I am aiming at. It's like an overlaying window on top of the full screen game interface.
Silver
October 4th, 2004, 07:12
Hm, in that case I'd inject some code based around DrawPrimitiveUP using RHW to make life easy. Shouldn't be too difficult, providing you make absolutely sure to get the calls inside a BeginScene()/EndScene() segment, and not to change (or at least reset) the renderstates after your rendering. Thinking about it, your best bet would be to add you code immediately before the Present() call, which would allow you to mess with the transforms and the renderstates without having to reset them. Shaders and multipass rendering are a no-no for this however.
If you have a live example, I'll be happy to code you a mini-DX app in C that you can rip the compiled code from to inject into something - would save you learning any DX (if you don't know any already?)...
homersux
October 8th, 2004, 10:24
Silver, I found it hard to understand what you just said in your previous message even though I am a code injection guru, that just shows you how much I know about directX stuff

Since I am fairly certain that a full screen mode windows media player uses directX (or not?), maybe you can demonstrate how to draw a text clock window over it? Besides being a demo, it's got some practical use as well.
Silver
October 9th, 2004, 10:42
Hehe

This could be interesting, because I'm a DirectX guru but firmly in the "noob" category for code injection.
Here's my thoughts, if we can work together on this. I'll code a simple app in C++ (DX in asm is a bit of an arse because of the COM and object issues) that uses DX to draw something (a clock is fine). I'll tag the function that does the actual clock drawing with some easy to locate code. I'll give you the exe, and you can pull the disasm of the function out of it. I'll then code a second app that does some D3D rendering (a cube or something), which we can use as a target. I'll then help you find the right location in the assembled target to call my clock code, and you can handle the injection part of it. End result should be the target with the clock code injected into it.
Windows Media Player is not necessarily a good target for our first attempt at this - it doesn't actually use D3D, it uses DShow. In simple terms, D3D is the 2D and 3D rendering interface for the DirectX suite, whereas DShow is the video rendering interface (hence the xvid/ffdshow *filter* - they are DShow filters). We can't use DShow COM methods to draw anything with ease, we need to use D3D. It's possible that WMP imports the D3D methods, but I'd rather try it on a sample exe where we can control both the target and the injection code - then move onto a live target.
If that makes sense to you, I'll go ahead and do it. If you have other ideas let me know - I'm really interested to see how you inject this code into a working sample, and would really like to try this little project...
JMI
October 9th, 2004, 11:05
Give some thought to making this a "mini-project" and moving the effort into that Forum and you might attract some additional help from others with some specialized knowledge on these topics. Just a thought.
Regards,
homersux
October 9th, 2004, 19:33
Here's my thoughts, if we can work together on this. I'll code a simple app in C++ (DX in asm is a bit of an arse because of the COM and object issues) that uses DX to draw something (a clock is fine). I'll tag the function that does the actual clock drawing with some easy to locate code. I'll give you the exe, and you can pull the disasm of the function out of it. I'll then code a second app that does some D3D rendering (a cube or something), which we can use as a target. I'll then help you find the right location in the assembled target to call my clock code, and you can handle the injection part of it. End result should be the target with the clock code injected into it.
--
Silver, this sounds like a fine plan to me. Please code 2 apps like you said and tell me which code is to be injected into which at what function entry. It's easy for me to dynamically inject code.
JMI, move this to mini project is a good idea.
JMI
October 9th, 2004, 20:03
Move to the Mini-Project Forum accomplished. I added a note to the first post explaining why it is here.

Good luck on your efforts.
Regards,
nikolatesla20
October 9th, 2004, 21:16
I've done this sort of work before - I made a game cheat that changed the Direct3D calls to change the draw mode to D3D_WIREFRAME, so you could see thru everything.
Hooking DirectX is the best way to go with this, it's easily possible and it actually used a lot for "cheats" as well as added functionality. Using an injection DLL would allow you to do some pretty elaborate things.
-nt20
homersux
October 9th, 2004, 22:57
What's the best way to learn directX? Graphics programming is really not my status quo.
Silver
October 10th, 2004, 08:55
Okay, I'll get on with coding those today and should be able to upload them later (bit busy right now).
homersux, learning D3D (DX is D3D, Dshow, DInput, Dplay, DSound etc, so for the graphics side just concentrate on D3D) is a fine art. Some people pick it up quickly, others find it impossible. It took me probably about a year to get good at it. The main issue is that you have to learn so much theory before you can even start putting it into practice, and the theory is way left of any other type of coding... There are a lot of good tutorial sites on the net though.
Silver
October 10th, 2004, 09:44
Okay, here we go. I've attached a zip to this message containing 2 exes and a bitmap. The bitmap is used for the texturemapping and is a bit irrelevant, I just used an old test app of mine for speed. They are both DX8 for no reason, I can convert to DX9 if you'd prefer but I didn't know what SDK or OS you have.
Target.exe is our target. Locate the push and call to MessageBox() starting at 4043AD (the params are something like "NOP THIS CALL" so you know you've got the right one). Nop that call, run the exe and you'll see a 3d cube. You need to inject your code precisely at this location, do not overwrite any bytes other than the MessageBox related stuff. The code immediately after it is D3D related that flips the backbuffer.
Inject.exe is our source. Locate the push and call to MessageBox() starting at 4316AD (again, params make it obvious so check the stack). Nop the call, you should see a shaded triangle drawn in the top left of the window. This Messagebox call is at the very top of the function that draws the triangle. The C++ code looks like this:
Code:
HRESULT InjectThis(LPDIRECT3DDEVICE8 pDevice)
{
MessageBox(NULL, "INJECT THIS CALL CODE", "SOURCE", MB_OK);
DWORD dwFVF_SIMPLEVERTEX = (D3DFVF_XYZRHW | D3DFVF_DIFFUSE);
typedef struct _tagSimpleVertex
{
float x,y,z;
float rhw;
D3DCOLOR dwDiffuse;
} SIMPLEVERTEX;
; snipped, setting up a local array for the triangle here
pDevice->SetVertexShader(dwFVF_SIMPLEVERTEX);
pDevice->DrawPrimitiveUP(D3DPT_TRIANGLELIST, 1, Triangle, sizeof(SIMPLEVERTEX));
return S_OK;
}
This code is entirely self contained, except for 1 parameter - the function param LPDIRECT3DDEVICE8. This is a pointer to the D3D COM object that lets us talk to D3D. I think this may be an issue, but I'll let you comment on my explanation. Note where this call occurs, immediately before calls to IDirect3DDevice8::EndScene() and IDirect3DDevice8::Present() (you'll spot the Present() call by 4 NULLs pushed to the stack).
When an app sets up D3D COM interfaces, it calls Direct3DCreate8() to intialise a COM interface, this is a wrapper call for CoCreateblahwhateveritis(). This call returns a pointer to a D3D top level COM object IDirect3D8. That pointer is then used to detect the capabilities of the graphics card via various COM method calls (known as D3DCAPS), and then to create the D3D device using IDirect3D8::CreateDevice(). IDirect3D8::CreateDevice() returns a pointer to a new COM object of the IDirect3DDevice8 interface. LPDIRECT3DDEVICE8 is a typedef for a pointer to a pointer to an IDirect3DDevice8 interface. It is this pointer, the device pointer, that we have to use to access all of D3D's methods. The issue we have is that there is no way to retrieve this interface pointer without a lot of messing. The normal process for a D3D app is that at some point it will call IDirect3D8::CreateDevice() and store the returned pointer in either a global variable, or in a class wrapper (probably as a static member or a singleton) for use by the rest of the app. So, in my very limited experience of code injection I think nikolatesla is correct in that we need to hook the CreateDevice() call to store the device pointer for ourselves.
Sorry if I just taught you to suck eggs, but wanted to be clear.
So, I see the next tasks as:
1. Rip the function from inject.exe
2. Make "necessary adjustments" to target.exe to retrieve the device pointer
3. Inject the function from inject.exe to target.exe
4. Supply the device pointer to the injected function.
Once we've done this, we can start extending the code a bit.
And this is where I check out and hand over to you

nikolatesla20
October 10th, 2004, 17:45
This is an interesting project, I'll definitely join in. I've done a bit of this type of work before.
Quote:
[Originally Posted by Silver]IDirect3D8::CreateDevice() returns a pointer to a new COM object of the IDirect3DDevice8 interface. LPDIRECT3DDEVICE8 is a typedef for a pointer to a pointer to an IDirect3DDevice8 interface. It is this pointer, the device pointer, that we have to use to access all of D3D's methods. The issue we have is that there is no way to retrieve this interface pointer without a lot of messing. The normal process for a D3D app is that at some point it will call IDirect3D8::CreateDevice() and store the returned pointer in either a global variable |
Since there is almost always a single instance of a Direct3D object, you can just disasm the code and find where EAX gets stored after the Direct3DCreate8 call.
Code:
push 0DCh
.text:004039CA call Direct3DCreate8
.text:004039CF mov dword_4D95A0, eax
.text:004039D4 cmp dword_4D95A0, 0
Notice here it's in a global variable at 004D95A0. Hence now all you need to know if the offset into this pointer (this pointer is actually a pointer to a vtable) and you can hook BeginScene. After a BeginScene call you can do any of your own code you want, although perhaps for drawing over the top of everything you might want to hook EndScene and add your drawing.
At one time I actually had record of the function offsets for BeginScene and EndScene, etc. But who knows where those notes are now

.
"PunkBuster" uses this type of technique to draw additional menus, etc. (at least it used to)
-nt20
nikolatesla20
October 10th, 2004, 22:00
Direct3DCreate8 returns pointer to IDirect3D8 interface:
general interface method invocation goes as follows:
Code:
mov eax, dword ptr 0xXXXXXXXX <- XXXXXXXX is global interface ptr location
mov edx, [eax] <- get vtable
mov ebx, dword ptr 0xXXXXXXXX <- interface ptr again, here it's "this" ptr.
push ebx
call dword ptr [edx + 0xXXh] < - call method in vtable.
We need to get Direct3DDevice interface ptr, so:
IDirect3D8 interface exposes function CreateDevice()
CreateDevice call = IDirect3D8 [vtable + 0x3Ch]
Device object ptr is
returned in address ptr [esp+0x1Ch] inside CreateDevice call.
In the demo "Target.exe", the device ptr is stored at 0x004D95A4
to get vtable of the device ptr:
mov eax, dword 0x<device ptr location>
mov ebx, [eax] <- we now have vtable ptr. in ebx
to call a function:
call dword ptr [ebx+0xXXh] < - call vtable method
Direct3DDevice offsets:
Code:
BeginScene - [vtable + 0x88h]
GetBackBuffer - [vtable + 0x40h]
SetMaterial - [vtable + 0xA8h]
SetLight - [vtable + 0xB0h]
SetTransform - [vtable + 0x94h]
EndScene - [vtable + 0x3Ch]
Present ???? [vtable + 0x8Ch]
DrawPrimitive - [vtable + 0x118h]
SetTexture - [vtable + 0xF4h]
If you have a Device pointer, you can invoke these functions using these offsets into that pointer.
-nt20
Silver
October 11th, 2004, 08:58
nikolatesla, that's very interesting, thanks for the info. One thing to add, multiple IDirect3DDevice8 interface instances is usually likely in either multi-monitor configurations or for some (strangely coded) utility apps that use multiple windows/views (think 3D modelling editor).
To add, some further functions that will be of use to us a pseudo-game cheat coders (all IDirect3DDevice8:: methods):
Code:
SetRenderState()
SetVertexShader()
DrawPrimitiveUP()
Clear()
I'd recommend that DrawPrimitiveUP() is always used in preference to DrawPrimitive for this. Although it's a big performance hit, for our purposes it's going to become quite awkward to manage vertex buffer swapping and binding through injection.
Some clarification of BeginScene(), EndScene() and Present(). BeginScene (BS) is used to tell D3D that you're about to start rendering to the backbuffer, so all locks should be checked. BS can be called automatically by some methods, especially D3DX utility library methods, therefore searching for BS calls is not necessarily going to find the "right" one. EndScene (ES) is used to close a BS block, and tells D3D that locks on the surface can be released. Present() tells D3D to page flip the back buffer to the front buffer for on-screen display. It's the last rendering action completed on every iteration of the rendering loop.
Where this becomes slightly more complex is that certain state changes cannot take place inside a BS/ES block. For example, you cannot change the rendertarget inside one of these blocks. There is also a performance hit for every BS/ES call, and Microsoft recommend you keep to 1 (or as few) BS/ES blocks where possible. This leads onto another consideration - multipass rendering. It's very common for apps to use multipass rendering to achieve certain effects. An explanation of why would take too long, but in summary it means that it's quite likely to find a call to a Render() function, and this function is called several times using switch() type functionality before Present() is called.
Think that's all I have relevant to contribute for the moment.
homersux
October 11th, 2004, 10:21
Silver, the target.exe crashed my computer.

I hope you didn't plant anything evil in that thing. The size is 904KB, amazingly big for such a simple application. Also it'd be useful if you could also include the source code and project file since I have no idea what programming semantics there is for d3d programming.
--
edit, the target.exe keeps crashing my computer, there is not much I can do.

win2k, directx 9c, and july 2004 directx (9c update) sdk here.
nikolatesla20
October 11th, 2004, 11:23
Well, I woudn't recommend hooking the actual functions themselves generically, rather it might be better to just disasm the app and now you could search for the Correct areas you want to inject.
BUT:
As far as multiple devices, I don't know of any game at this time that supports them. Multipass is a good argument, but you could simply find in the disasm where you wanted to hook your code - besides, in a multipass you might wish to render your object each time, so it didn't get erased by one of the multipasses. I disasmed Raven Shield, and even that game only contained one BeginScene call. Multipass is really the only time you'll get more than one BeginScene(), since most game engines are built around an object tree:
BeginScene()
RenderAllObjects walking the list of objects
EndScene()
is usually the way it's done.
If you want to change the state to wireframe, etc, you have to override the SetRenderState like you mentioned. That's actually a good function to also record down.
You'll always have to know the function offsets somehow.
In the DX9 SDK I have now, I got these just this morning. Just throw messageboxes in your code before any Direct3DDevice call, and then disasm it to find where the call goes
That's the overall problem, is sometimes these offsets will be application specific as well. (Or usually DX version specific)
BeginScene [ vtable + 0xA4h]
Present [vtable + 0x44h]
SetRenderState [vtable + 0xE4h]
EndScene [vtable + 0xA8h]
GetBackBuffer [vtable + 0x48h]
The purpose of using these pointers isn't just to have the ability to call them, it's also so you can find in the code where you should override with your own code. With an already compiled EXE you should be able to use the Direct3DCreate8 call, which is the only Direct3D import, and walk from there to find the CreateDevice call, and then use the Device ptr to find where BeginScene(), etc get called. You should learn to be able to do this manually in your disassembler. If you can't do this, you won't be able to inject any code in your target. Step one is recognizing these common structures and offsets to calls so you can find the location you need to hook into.
-nt20
Silver
October 11th, 2004, 12:22
nikolatesla, thanks, I understand better now. I'll have a go at this tomorrow when I have some more time.
I have to raise one objection to what you said though. It's an absolute requirement of D3D that you cannot be in a BeginScene/EndScene block when changing the rendertarget. That means that any effects such as cubic environment mapping, spheremapping etc will show at least 2 blocks. How common they are in commercial games, I don't know. They are very common in demos/intros.
homer, I've attached a new zip to this message. It contains the inject.exe and the target.exe with a parameter slightly altered. I'm guessing the crash was because your card doesn't support lockable backbuffers properly, so please try the inject.exe out (you can just OK the messageboxes to make sure it works). I've also included a VC6 workspace for the inject.exe code. It will show you the structure of a D3D app, the calls and setup sequence and how I rendered a simple tri in the injection function. I didn't bother including the source for the lit cube because that contains lots of extra rubbish that just confuses the issue.
Let me know if you still have issues with getting the code running. If you have Visual C, you can load the inject workspace, comment out the messagebox call then run it with debug to see any debug spew that might indicate a problem.
The large size of the previous exe was because I built it as debug, sorry. These are built as release but are the same code, so you'll be able to find the messagebox calls just like before.
nikolatesla20
October 11th, 2004, 21:22
Here's an injected version I made,
I added a new section to the PE with LordPE, ripped the code bytes from inject EXE, and put them in the new section. Then I NOPPED the MsgBox code in the target, and changed it to:
mov eax, 0x44c764
mov ecx, [eax]
push ecx
call 00450000
pop ecx
nop
nop
nop
nop
<nop until good code>
And this works fine. It's easier since the inject code uses all local variables

, and it gets the device object ptr passed in as an argument, so it's not too bad.
Apparently however Direct3D does not care rendering with different vertex shaders and weird stuff happens. While I get both to draw, the cube jerks around strangely.
-nt20
Silver
October 12th, 2004, 07:07
Nice job. I'm not sure why it's jerking on your machine - does the original cube on its own exhibit the same symptoms (eg: nop the messagebox in target.exe and run it like that)? It might be your gfx card, an incompatibility with the D3DCAPS, or it might be something I forgot on the D3D side.
I'll run it on my d3d coding machine when I get home and see what I can figure out. I'll poke around in your targetinjected.exe deadlist too
Here's another thought on this miniproject. It was easier for you to inject this code because of the (effectively) dead bytes where the Messagebox() call was. How would you go about injecting this same code if you didn't have the dead bytes to use? Bearing in mind, you're very restricted on where you can call your injected code (unless you do something cunning like render the injected gfx with a high Z-bias so they always get drawn on top...). You could move bigger chunks of code into the injected call, but then you've got to worry about vars being used...
So, I propose the next stage for this is to add keyboard input. I'll code another inject.exe that (for example) sets wireframe, point and fill mode rendering. Task is to manipulate the messageloop to trap a keypress, and call the injected function to change the rendering mode (for example, pressing + cycles between point, line and fillmode). Unless anyone has better ideas

nikolatesla20
October 12th, 2004, 08:51
Nope, nothing wrong with my video card, I got latest Nvidia stuff, the target.exe runs fine on its own.
Actually if you NOP the messagebox the cube rotates weird period, it jerks around, so I think it's a problem with your code , sorry
Oh, and about rendering with a high z-bias: You don't need to do this if you set the VertexShader to use 2D only coordinates. The renderer then will draw stuff straight up on the viewport, and won't do any depth calculation on it. (Set your FVF to be already-transformed-coordinates).
I'd say for injection purposes you can pretty much take over anywhere betwen BeginScene() and EndScene() if you want, depending on what you want to do. For example, if you are drawing a UI over the top, you could probably get away with drawing it at any time, and use 2D FVF's. But if you want to make walls transparent, but people not, you'll have to find in the code where walls get drawn and do your work there. If you want everything transparent, it's easy to just find a SetRenderState anywhere and play with it, keep playing with RenderStates you find until you hit the right one. (You can narrow it down by looking at the arguments that get passed to SetRenderState to see if they are D3DRS_SRCBLEND or DESTBLEND).
As you can see from this newly attached example, vertices that are FVF's with XYZRWH will not get sent thru the 3D translation engine (they are assumed to already be translated to screen coordinates), therefore they draw on top of everything else if you have a z = 0.0f. In the example the triangle is now drawn over the top of the rotating cube.
-nt20
homersux
October 12th, 2004, 10:14
ok, new target.exe works. let's see now what was the original goal we wanted to achieve? UI ontop of a d3d rendering?
--
Geez, man there is something wrong with your target.exe, the first time it executes fine but it crashes on the 2nd run. I am using a laptop without a real 3d card. But it's probably got bugs in the code. I have done basically the same thing nico has done and the code injection is pretty easy. But the question is if this is the kind of stuff that works for a commercial game?
Ok after rebooting about 4-5 times,

this is my version of injected target, iI added a new section .inj 4k bytes long and copy/pasted injecthere code. It works fine and shows both cube and triangle.
Silver
October 12th, 2004, 12:59
Quote:
Actually if you NOP the messagebox the cube rotates weird period, it jerks around, so I think it's a problem with your code , sorry |
hrm, if I knew my code was on trial, I'd never have started

. Bit strange though, works fine here. This is one problem with D3D, if you don't set up the caps properly it won't work everywhere. What GFX card do you have?
Quote:
Oh, and about rendering with a high z-bias: You don't need to do this if you set the VertexShader to use 2D only coordinates. <snip> For example, if you are drawing a UI over the top, you could probably get away with drawing it at any time, and use 2D FVF's |
Yup, but then you are completely restricted to 2D stuff, so can't do cool things like put a minature version of a 3D map in the corner
Quote:
therefore they draw on top of everything else if you have a z = 0.0f |
Actually they'll be drawn on top anyway, the Z component is ignored, it's the RHW component of the FVF/vertex struct that matters.
homer: If you've just got a built in card, it's definately the caps that are the problem. It's awkward and long winded to set up all the caps properly , you effectively have to test each cap, check the return result then use that result to set the actual cap. And there's a hell of a lot of caps - if you have the SDK, look for the DirectX Caps Viewer in the DX Utilities dir. So in summary, I was lazy and didn't set them up properly
Quote:
But the question is if this is the kind of stuff that works for a commercial game |
Yes, it does. Believe it or not I've coded a commercial game (and on the basis of this crappy code, feel free to not believe it

) and the major difference between a game and this sample is that a game will have some kind of base engine to separate the "gameplay" code from the game mechanics, so the D3D device creation will be sandwiched inside a load of other junk. I'm a better coder than reverser, honest

homersux
October 12th, 2004, 13:29
It seems the difficulty in a real world example is:
1) finding the location of the p_Device, in this example, it's straightforward once the target is disassembled (it's got a similar code structure with inject).
2) locating a point for code injection, somewhere between BeginScene and EndScene. In this example, we used static code inject, 2 cons 1) exe integraty check will dismiss the attempt 2) needs to rewrite part of original exe or save/restore in new code segment--lots of
code rewrite 3) injected code may be complicated and has non-local data references, in our exercise inject code is nice and compact
So if I was to attack something more seriously, it means I'll be using dynamic code injection and will patch code on the fly. The added benefit is load/unload patch at will.
nikolatesla20
October 12th, 2004, 14:27
Well, homersux, the only difference with dynamic injection is:
1. Allocate memory in the other process with VirtualAllocEX
2. Relocate any memory location-dependant code in your injection snippet to compensate for location of remote memory.
3. Inject the code (write it) into the remote memory
4. Write out the small bit of hook code that causes the EXE to jump
to your newly injected code
It's that simple. Relocation is actually the hardest and boringist part (if you have to relocate addresses in your injection code).
Yes, you pretty much always have to either disasm or debug the game live so you can find the appropriate place to inject.
You could write more advanced code that would start the game EXE and then hook into its Direct3D functions so it would work on more than one game, but it still would be D3D version dependent (since the offsets to methods will be different between an IDirect3D8 and IDirect3D9 interface), and also is a bit more work. But it can be done. In fact, since DirectX is COM based, even though the interfaces are different, you should be able to query the DirectX 9 interface for a DirectX 8 interface pointer thru QueryInterface(). QueryInterface() should be the very first function pointer in the vtable. If you know the interface ID (IID) of the IDirectX8 interface, you could write your code to use DirectX 8 and just always query for this interface in your injection.
However, this is just theory right now
Silver: I'm using a Nvidia GeForce2 Ti at work, and a NVidia GeForce4 440MX at home, and it acts the same on both systems. I'll check my modded code again.
-nt20
homersux
October 12th, 2004, 17:26
silver, what're the differences between window mode and full screen d3d? It seems window mode uses a backbuffer or some sort just from reading your code.
Silver
October 14th, 2004, 06:33
Quote:
what're the differences between window mode and full screen d3d |
Well the main difference is that in windowed mode, the D3D front and back buffer surface format must be configured to be the same as the Windows desktop format (bit depth), as well as other params like refresh rate etc. In full-screen mode you have complete control over all display parameters.
Both windowed and fullscreen use a backbuffer and frontbuffer page flipping system, it's just windowed mode is far more dependant on Windows...
nikolatesla, you said:
Quote:
If you know the interface ID (IID) of the IDirectX8 interface, you could write your code to use DirectX 8 and just always query for this interface in your injection. |
Not sure I follow, from the context you wrote this in are you saying that you can use DX8 interfaces for a DX9 injection/hack? If so, I'd disagree.
As a side thought, in a real world example I would think a good approach would be to locate the app's d3d engine wrapper functions and to call those directly. Because doing basic things like drawing boxes and blitting text is such a pain with D3D, every non-trivial app I know of uses at least a wrapper of some sort (eg, MyEngine::TextOut(...) wraps text blitting functions etc), if not a full engine. It would make sense to use these functions where possible, to minimize the amount of work you would have to do in the injected code, not just to reduce the code but also to reduce the dependancies on caps and config.
nikolatesla20
October 14th, 2004, 07:06
Quote:
[Originally Posted by Silver]
As a side thought, in a real world example I would think a good approach would be to locate the app's d3d engine wrapper functions and to call those directly. Because doing basic things like drawing boxes and blitting text is such a pain with D3D, every non-trivial app I know of uses at least a wrapper of some sort (eg, MyEngine::TextOut(...) wraps text blitting functions etc), if not a full engine. It would make sense to use these functions where possible, to minimize the amount of work you would have to do in the injected code, not just to reduce the code but also to reduce the dependancies on caps and config. |
This is a good thought , you should be able to use the functions in the dxd8/9 libraries since they are DLLs and should be in the other process. It would be interesting to try using those.
-nt20
homersux
October 15th, 2004, 09:25
ok, so now can we have some code to be injected to target and displays
a clock in text?

Silver
October 15th, 2004, 13:06
hehe, sure thing. I'll do that this weekend. This may be harder to inject as we'll need to create global objects in the target for the injection code. I'll post here when I've done it.
edit 20/10 - my apologies, I've been really busy the last few days. I'll get this done as soon as I have a bit of spare time. I have a nightmare deadline coming up for coursework material I'm writing

goggles99
February 28th, 2005, 13:52
This topic is VERY interesting and informative. I just happen to be working on a D3d game trainer and I would like to add a status menu of sorts to display in-game.
Would anyone here happen to have any of the zip files which were attached to this topic? They are all corrupted (since this forum went down). If possible, could you re-up them here?
Thanks a lot
Also, Silver, nikolatesla20, and homersux. Would you mind if I use the info in your posts here to make a tutorial?
I will (of course) credit your names.
Silver
March 1st, 2005, 13:29
No problem on my part. I never did have time to continue this, unfortunately. Let me know if you would like any DX-specific help with your tut, as this thread is very basic from a DX point of view. I've also apparently misplaced the code I wrote, perhaps homer or nikola still have it along with their injection.
homersux
March 7th, 2005, 17:21
Let's see if I still have the files.
goggles99
March 19th, 2005, 15:02
Thank you Silver and homersux...
I now have all I need to get going

Opcode
April 22nd, 2005, 06:26
Quote:
[Originally Posted by bilbo]
How it obtains this info? It reads from the registry a list of the video drivers used by the system (kernel DLLs), and hooks their entry point, which is DrvEnableDriver(), using a powerful hooking engine.
In this way it obtains a pointer to the driver structure DRVENABLEDATA, and it can hooks all the interface functions exported by the driver.
Regards, bilbo |
How can I find these registry entries? Where are they?
I'm reading the DDK about video drivers but I'm not
able to find where win32k.sys/ntosknl.exe find and load
the video drivers DLLs!
Thanks for any help!
Regards,
Opcode
bilbo
April 22nd, 2005, 07:09
Sorry, Opcode, if I was confusing you...
The registry entries are not system-wide entries, but NTICE ones, and their are set at installation time:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\NTice\InstalledDisplayDrivers to enable the hooking
and
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\NTice\ExcludedDisplayDrivers to disable it
Regards, bilbo
Opcode
April 22nd, 2005, 07:16
Thanks bilbo!
This is my problem exactly:
01. I know how to create a video driver dll.
02. I want that the Windows graphics subsystem load my
driver dll. I'm supposing that is the win32k.sys
that will load it.
03. I just don't know what registry key I need to
create to make win32k.sys load my driver.
This is because I want to put a INT 0x03 opcode
inside the DrvEnableDriver function to see how the
graphics subsystem works internally.
I appreciate any help... and Google didn't help me!
Regards,
Opcode
bilbo
April 22nd, 2005, 10:09
As for the registry entries, they are plunged into CurrentControlSet...
Search the registry for your current DLL name (e.g. MGAUD, IALMRNT5), the same detected inside the NTICE entry.
As for INT03, I am afraid you cannot set a breakpoint so early in the system life, and I don't know if VMWare (or, better: the debug version of Bochs) can help you for a sofisticated video...
You should use (aargh!) M$ WinDbg with a cable connection to another computer...
Best regards, bilbo
Powered by vBulletin® Version 4.2.2 Copyright © 2018 vBulletin Solutions, Inc. All rights reserved.