Cheat Engine Forum Index Cheat Engine
The Official Site of Cheat Engine
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 


Getting directx frame into a buffer

 
Post new topic   Reply to topic    Cheat Engine Forum Index -> General Gamehacking
View previous topic :: View next topic  
Author Message
Chris12
Expert Cheater
Reputation: 1

Joined: 27 Apr 2012
Posts: 103

PostPosted: Fri May 15, 2015 4:48 pm    Post subject: Getting directx frame into a buffer Reply with quote

Hi,

i want to get image data from a game (dx9) with cheatengine.
my idea was to hook some directx function (endscene, present, ... ?) and then get a pointer to the pixel data there.

I intended to allocate a large enough block of memory to hold a frame in the game process and then write the data to this buffer.

Getting the image into a separate buffer inside the game memory would be enough for me to continue. Pixelformat doesn't matter.

But what directx function do I use?
How would I get the directx interface?
How do I get the pixel data when I'm in the function.

I have no problems with the hooking itself or writing the assembler.
But I never really worked with directx before.

Is what I described possible? If so how?
Back to top
View user's profile Send private message
atom0s
Moderator
Reputation: 205

Joined: 25 Jan 2006
Posts: 8585
Location: 127.0.0.1

PostPosted: Fri May 15, 2015 9:57 pm    Post subject: This post has 1 review(s) Reply with quote

There are few different ways you could go about doing it.

Keep in mind access to the back buffer is dependent on if its lockable. In most cases it wont be by default so you may need to do some extra work to make it lockable if you go that route. The method I use the most in my projects is just locking the back buffer and using its data.

Firstly, you will have to ensure the back buffer is lockable. This is done with the creation flag 'D3DPRESENTFLAG_LOCKABLE_BACKBUFFER' set as one of the present parameters 'Flags' field. Keep in mind as well there are limits to using this flag and it does have a performance hit on certain cards. So use with care.

In order to set this you will need to hook:
- IDirect3D9::CreateDevice
- IDirect3DDevice9::Reset (The present parameters can be rewritten here so you want to hook it and reset the flag as needed.)

Afterward you can hook Present or EndScene to obtain the back buffer as needed and do what you will with the pixel data.
Something like this:
Code:
HRESULT __stdcall wrappedIDirect3DDevice9::EndScene(void)
{
    if (SUCCEEDED(this->m_Direct3DDevice9->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &this->m_BackBuffer)))
    {
        if (SUCCEEDED(this->m_Direct3DDevice9->GetRenderTarget(0, &this->m_RenderTarget)))
        {
            if (this->m_BackBuffer == this->m_RenderTarget)
            {
                // The back buffer is the render target so use it as you wish..
            }
        }
    }

    // Cleanup..
    SAFE_RELEASE(this->m_BackBuffer);
    SAFE_RELEASE(this->m_RenderTarget);

    return this->m_Direct3DDevice9->EndScene();
}


To get the pixel data, you have to use the 'LockRect' method to obtain a pointer to the pixel data.

Depending on the game and setup you may need to do your work inside of BeginScene or Present. Really depends on the game. BeginScene/EndScene can be called multiple times before Present is called to render the data to the screen, so test things out to see how the game is setup for your needs.

_________________
- Retired.
Back to top
View user's profile Send private message Visit poster's website
Chris12
Expert Cheater
Reputation: 1

Joined: 27 Apr 2012
Posts: 103

PostPosted: Sat May 16, 2015 12:54 pm    Post subject: Reply with quote

Thanks,
so CreateDevice and Reset to modify the flag; BeginScene, EndScene or Present to get the image.

If possible I'd like to write all this in assembler, no dll injection.
But getting all offsets dynamically will be quite a bit of work I think.

What do you think would be the easiest way to get all the functions and struct offsets? like the offset of m_RenderTarget?

I'm not the first person who does this so maybe someone even has a list of offsets for every function and struct member^^
If not I guess I'll get them by injecting a dll, read the function addresses, subtract the d3d9 base and dumping them to a file or something...

endscene should be d3d9.dll+0x1ce09 right?
Back to top
View user's profile Send private message
atom0s
Moderator
Reputation: 205

Joined: 25 Jan 2006
Posts: 8585
Location: 127.0.0.1

PostPosted: Sun May 17, 2015 1:49 am    Post subject: Reply with quote

Pointers like that wont be reliable since systems can have different versions of Direct3D installed which can get used while the game loads. So hard coding any offset like that will result in major issues.

Since you are working with Direct3D9 there is a signature trick to locate the device pointer that works universally.
Pattern: "\xC7\x06\x00\x00\x00\x00\x89\x86\x00\x00\x00\x00\x89\x86"
Mask: "xx????xx????xx"

Or you could write a proxy that hooks and wraps the entire d3d9 dll.

As for the offsets, you can just take the interface from d3d9.h and determine them manually. Once you have the device pointer, you are just working with a vtable. So you would take the index of the function, multiply it by 4 and add that to the device pointer to get the function address.


From the sound of it you are trying to do this externally, which is not going to really work in your favor and is going to land up being a shit-ton more work then is needed if you just instead, injected a dll.

_________________
- Retired.
Back to top
View user's profile Send private message Visit poster's website
Chris12
Expert Cheater
Reputation: 1

Joined: 27 Apr 2012
Posts: 103

PostPosted: Sun May 17, 2015 2:00 pm    Post subject: Reply with quote

many thanks for the pattern.
yea with the vtable it should be np.
member offsets (struct fields) are unlikely to change between versions i guess.

yes, what im trying is to write all the code with fasm, inject it myself and then just read the image data from the outside, with mutex lock to prevent frame tearing.

i agree it will be more work, but im not really comfortable with writing c++, but asm is no problem. Maybe i'll use a c# dll, there's a way to get "normal" dll exports to work in them too.
Back to top
View user's profile Send private message
atom0s
Moderator
Reputation: 205

Joined: 25 Jan 2006
Posts: 8585
Location: 127.0.0.1

PostPosted: Sun May 17, 2015 3:14 pm    Post subject: Reply with quote

Chris12 wrote:
many thanks for the pattern.
yea with the vtable it should be np.
member offsets (struct fields) are unlikely to change between versions i guess.

yes, what im trying is to write all the code with fasm, inject it myself and then just read the image data from the outside, with mutex lock to prevent frame tearing.

i agree it will be more work, but im not really comfortable with writing c++, but asm is no problem. Maybe i'll use a c# dll, there's a way to get "normal" dll exports to work in them too.


Offsets in the vtable wont change for Direct3D9 dll's. The only thing you may find different is if the device is created with Direct3DCreate9 or Direct3DCreate9Ex. And then, then only different is more functions are added to the end of the device pointer with 'Ex'.

From the sound of what you are doing, an idea would be to use an IPC.

Inject your DLL into the game and do the hooks as needed. Inside of whichever thing you hook (BeginScene, EndScene, or Present) you can do the locking for the image data and such. I would then suggest you immediately copy that buffer to a different object of memory that your hook owns and allow the game to continue running as normal to prevent FPS loss or tearing. Next, I would say send that buffer to an IPC method of your choice. Be it, MMF's, named pipes, mailslots, or similar, but then your eternal application could receive the buffer and use it as needed.

That way you could help reduce FPS loss and such.

If you do plan on using C#, you could check out EasyHook. There are a handful of Direct3D hook examples using that.

_________________
- Retired.
Back to top
View user's profile Send private message Visit poster's website
Chris12
Expert Cheater
Reputation: 1

Joined: 27 Apr 2012
Posts: 103

PostPosted: Sun May 17, 2015 4:32 pm    Post subject: Reply with quote

I already tried a lot of code from the internet using easyhook, but its not as stable and fast as I hoped it would be.
so i decided to do it myself and mis-use readprocessmemory+mutex as a sort of ipc.

If all fails I think I'll just combine that copy to buffer thing with easyhook.
btw you're a great help. thanks Smile
Back to top
View user's profile Send private message
atom0s
Moderator
Reputation: 205

Joined: 25 Jan 2006
Posts: 8585
Location: 127.0.0.1

PostPosted: Sun May 17, 2015 9:12 pm    Post subject: Reply with quote

Chris12 wrote:
I already tried a lot of code from the internet using easyhook, but its not as stable and fast as I hoped it would be.
so i decided to do it myself and mis-use readprocessmemory+mutex as a sort of ipc.

If all fails I think I'll just combine that copy to buffer thing with easyhook.
btw you're a great help. thanks Smile


I would recommend writing your hook in C/C++ or ASM that is injected. It will be much much faster for you. You can easily implement the IPC method of your choice as well and interact with it in an external C# application easily. For speed and stability, I would recommend using MMF's and writing your own custom protocol to handle pulling data from the MMF and such.

From industry experience, I've personally had nothing but issues with named pipes on anything that is extremely intensive on read/writing constantly. MMFs, out-performed in every possible test I did. Another really really good and stable IPC method is using sockets. A library I've used for another project was ZeroMQ. It is very fast and very stable.
http://zeromq.org/

It has wrappings for use with C# and a ton of other languages as well.

_________________
- Retired.
Back to top
View user's profile Send private message Visit poster's website
Chris12
Expert Cheater
Reputation: 1

Joined: 27 Apr 2012
Posts: 103

PostPosted: Wed May 20, 2015 10:08 pm    Post subject: Reply with quote

i hope this is still somewhat on topic,
but is it theoretically possible (if i can grab the dx device from the target process) to sort of "hijack" its device in my own process and directly grab image frames with it?

like sharing a hdc with gdi (drawing onto another process' window).

it works with the desktop, so wouldn't it work with other processes too?

similar to the code inside this:
http://www.codeproject.com/Articles/274461/Very-fast-screen-capture-using-DirectX-in-Csharp
Back to top
View user's profile Send private message
atom0s
Moderator
Reputation: 205

Joined: 25 Jan 2006
Posts: 8585
Location: 127.0.0.1

PostPosted: Thu May 21, 2015 2:18 am    Post subject: Reply with quote

A device context is handled within the given processes memory space. Taking the pointer to it and using it inside of your own memory will not work.

The example you linked to is doing nothing more then creating a new device within its own memory space and obtaining the front buffer of the screen. This works because they are using the desktop HWND as the target in the device creation.

_________________
- Retired.
Back to top
View user's profile Send private message Visit poster's website
Chris12
Expert Cheater
Reputation: 1

Joined: 27 Apr 2012
Posts: 103

PostPosted: Thu May 21, 2015 12:39 pm    Post subject: Reply with quote

But wouldn't it be possible to use the target process' window as target instead of the desktop?
or is the desktop special?
Back to top
View user's profile Send private message
atom0s
Moderator
Reputation: 205

Joined: 25 Jan 2006
Posts: 8585
Location: 127.0.0.1

PostPosted: Thu May 21, 2015 2:51 pm    Post subject: Reply with quote

Chris12 wrote:
But wouldn't it be possible to use the target process' window as target instead of the desktop?
or is the desktop special?


You can use another windows hWnd. I do not think there are limitations to that.

_________________
- Retired.
Back to top
View user's profile Send private message Visit poster's website
Display posts from previous:   
Post new topic   Reply to topic    Cheat Engine Forum Index -> General Gamehacking All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Powered by phpBB © 2001, 2005 phpBB Group

CE Wiki   IRC (#CEF)   Twitter
Third party websites