Page 1 of 2 12 LastLast
Results 1 to 25 of 34

Thread: RS3 DirectX Intercept/Hook - Identifying rock types

  1. #1
    Join Date
    May 2015
    Posts
    11
    Mentioned
    0 Post(s)
    Quoted
    9 Post(s)

    Default RS3 DirectX Intercept/Hook - Identifying rock types

    Hi,

    After successfully hooking DirectX, I was able to detect the whereabouts of mining rocks which were easy to identify during calls to DrawIndexedPrimitive(...). This is sufficient for most objects in the game. The various types of trees for example, are easily identified using this method. However rock types seem to be somewhat more illusive!

    Running RS3 with the "Medium" graphics presets, all rocks appear to consist of two primitives. One primitive models the main body of the rock which has a common appearance across all rock types, while a second primitive models the colored segments of the rock.

    As the appearance of the second primitive varies with each rock type and has a color to represent each rock type (Copper, Iron etc), this appears to be the primary point of interest. My first thought was to call GetTexture() during the DrawIndexedPrimative call and produce a CRC of the texture's data. However this produces an identical CRC regardless of the rock type.

    I've since spent far too long inspecting the data obtainable with most "IDirect3DDevice9::Get..." functions, however I have not found any information which can be used to reliably differentiate between the rock types. It's also interesting to note that if I save all of the textures created during calls to CreateTexture() and those which are encountered during DrawIndexedPrimative(), none resemble the color of a Copper, Iron, Mithril rock etc, however the various grass and ground textures are clearly identifiable.

    At this stage, I could have saved a great deal of time using color based techniques to identify the rock, however a DirectX solution would yield many advantages in terms of performance and reliability.

    If you have successfully used OpenGL or DirectX hooking methods to identify rock types, any information would be appreciated. I have even considered that Jagex are deliberately rendering this particular part of the rock outwith DirectX haha... I'm probably just looking in the wrong place.

    Thanks!

  2. #2
    Join Date
    Jan 2012
    Location
    Long Island, NY
    Posts
    413
    Mentioned
    5 Post(s)
    Quoted
    95 Post(s)

    Default

    You should use the new OpenGL library made by Obscurity and Clarity, it's pretty good and easy to program with.

    I don't know exactly what is going on with the models for the rocks, but I would imagine that the model is composed to be a dynamic object. You said the base for the rock is the same across all ore types, so I would say the model is compiled as a single model and texture. The model consisting of 2 attachments, the base and the ores themselves. The game is rendering an idle animation, and a depleted animation which displays 2 attachments for the first mentioned, and only one for the later. The texture could easily be colored by the engine as say an additive mix of the color of the ore over the texture that makes up the ore. I don't really know because I haven't seen your outputs or textures but I'm just basing it off how I've handled models like that in games before, as a 3D modeler of course. But because I think it's working with attachments based on animations(animation doesn't mean it moves just its bone position) it might not be displaying them as different models because they aren't. Like I said, just my thoughts not sure what they really do.

  3. #3
    Join Date
    May 2015
    Posts
    11
    Mentioned
    0 Post(s)
    Quoted
    9 Post(s)

    Default

    Quote Originally Posted by Brotein View Post
    You should use the new OpenGL library made by Obscurity and Clarity, it's pretty good and easy to program with.

    I don't know exactly what is going on with the models for the rocks, but I would imagine that the model is composed to be a dynamic object. You said the base for the rock is the same across all ore types, so I would say the model is compiled as a single model and texture. The model consisting of 2 attachments, the base and the ores themselves. The game is rendering an idle animation, and a depleted animation which displays 2 attachments for the first mentioned, and only one for the later. The texture could easily be colored by the engine as say an additive mix of the color of the ore over the texture that makes up the ore. I don't really know because I haven't seen your outputs or textures but I'm just basing it off how I've handled models like that in games before, as a 3D modeler of course. But because I think it's working with attachments based on animations(animation doesn't mean it moves just its bone position) it might not be displaying them as different models because they aren't. Like I said, just my thoughts not sure what they really do.
    Thanks for your reply!

    I had suspected that a common base texture was in use across all ores, the appearance of which is then altered. This is certainly what the texture CRCs suggest.

    Interestingly enough, if I pass my own texture to SetTexture before the DrawIndexedPrimative call, for example, a bright pink texture, there is still a noticeable difference in color between the rock types. They are different shades of pink. This would suggest that another influence is at play, perhaps a pixel shader or vertex shader. After a fair bit of digging, around inside the VertexShader and PixelShaders at the time of the DrawIndexedPrimitive call, I was unable to find any uniquely identifiable data.

    I'll be sure to provide some screenshots when I reach the 5 post requirement.

    For clarity, there appears to be two calls to DrawIndexedPrimitive for each rock; one for the base and another to represent the colored ore.
    Last edited by Kimon; 05-08-2015 at 08:27 PM.

  4. #4
    Join Date
    Jun 2007
    Location
    The land of the long white cloud.
    Posts
    3,702
    Mentioned
    261 Post(s)
    Quoted
    2006 Post(s)

    Default

    Quote Originally Posted by Kimon View Post
    Thanks for your reply!

    I had suspected that a common base texture was in use across all ores, the appearance of which is then altered. This is certainly what the texture CRCs suggest.

    Interestingly enough, if I pass my own texture to SetTexture before the DrawIndexedPrimative call, for example, a bright pink texture, there is still a noticeable difference in color between the rock types. They are different shades of pink. This would suggest that another influence is at play, perhaps a pixel shader or vertex shader. After a fair bit of digging, around inside the VertexShader and PixelShaders at the time of the DrawIndexedPrimitive call, I was unable to find any uniquely identifiable data.

    I'll be sure to provide some screenshots when I reach the 5 post requirement.

    For clarity, there appears to be two calls to DrawIndexedPrimitive for each rock; one for the base and another to represent the colored ore.
    I'm not sure if you've seen Brandon's GitHub project: https://github.com/Brandon-T/Genevieve

    And these posts about dx hooks: https://villavu.com/forum/showthread...38#post1312438

  5. #5
    Join Date
    May 2015
    Posts
    11
    Mentioned
    0 Post(s)
    Quoted
    9 Post(s)

    Default

    Quote Originally Posted by The Mayor View Post
    I'm not sure if you've seen Brandon's GitHub project: (URL)

    And these posts about dx hooks: (URL)
    Indeed, I spotted that thread a few days back. Very interesting stuff!

    These replies in particular:

    Quote Originally Posted by riwu View Post
    Is there any extra info to hook from models? Different type of mining rocks have the same model ID, so i have to find color within a box of the model point returned, which makes the ore finding more color-based than hooking based...
    Quote Originally Posted by Brandon View Post
    There is.. but I don't have much time to hook it or dive into hooking it. I heard Jagex fixed OpenGL bugs, yeah?

    Everything in RS has a texture. That includes models. If you hook model textures and save them, you'd hash them, you'd have unique ID's per rock model. You could also hook the vertices for each model. Similar to the Direct-X hook code that's on github.
    As far as I have been able to investigate, it looks like all rock types use the same texture. (I could be wrong!)
    It's possible that calling IDirect3DDevice9::GetTexture() during the DrawIndexedPrimitive call is insufficient, however from the perspective of DrawIndexedPrimitive, the vertex shader function data and pixel shader function data also yield no unique data.

    I would love to hear @Brandon's input regarding the rock textures, and indeed any method that can be used to identify the various types of rock.

  6. #6
    Join Date
    Feb 2011
    Location
    The Future.
    Posts
    5,600
    Mentioned
    396 Post(s)
    Quoted
    1598 Post(s)

    Default

    Quote Originally Posted by Kimon View Post
    Indeed, I spotted that thread a few days back. Very interesting stuff!

    These replies in particular:





    As far as I have been able to investigate, it looks like all rock types use the same texture. (I could be wrong!)
    It's possible that calling IDirect3DDevice9::GetTexture() during the DrawIndexedPrimitive call is insufficient, however from the perspective of DrawIndexedPrimitive, the vertex shader function data and pixel shader function data also yield no unique data.

    I would love to hear @Brandon's input regarding the rock textures, and indeed any method that can be used to identify the various types of rock.

    1 word: Interleaving. DrawIndexedPrimitive is used because textures, colours and vertices can be interleaved and rendered in a single call.

    Example, a vertex can be represented by:

    C++ Code:
    typedef struct
    {
        float X, Y, Z, RHW;
        unsigned int Colour;
        float U, V;
    } D3DVertex;

    OR:

    C++ Code:
    typedef struct
    {
        float X, Y, Z;
    } D3DVertex;

    OR other variations. But again, you can see that the "Colour" field is the colour of THAT specific vertex. If Jagex uses an array of said structure (and they do in some places), the colour would be the representation for EACH vertex; where U, V are the normals and RHW is the Reciprocal Homogeneous W.

    Also, textures are very very tricky to hook so make sure you actually have it done right. Otherwise that would be one reason all the hashes are the same or 0.
    Last edited by Brandon; 05-09-2015 at 01:49 AM.
    I am Ggzz..
    Hackintosher

  7. #7
    Join Date
    May 2015
    Posts
    11
    Mentioned
    0 Post(s)
    Quoted
    9 Post(s)

    Default

    Quote Originally Posted by Brandon View Post
    1 word: Interleaving. DrawIndexedPrimitive is used because textures, colours and vertices can be interleaved and rendered in a single call.

    Example, a vertex can be represented by:

    C++ Code:
    typedef struct
    {
        float X, Y, Z, RHW;
        unsigned int Colour;
        float U, V;
    } D3DVertex;

    OR:

    C++ Code:
    typedef struct
    {
        float X, Y, Z;
    } D3DVertex;

    OR other variations. But again, you can see that the "Colour" field is the colour of THAT specific vertex. If Jagex uses an array of said structure (and they do in some places), the colour would be the representation for EACH vertex; where U, V are the normals and RHW is the Reciprocal Homogeneous W.

    Also, textures are very very tricky to hook so make sure you actually have it done right. Otherwise that would be one reason all the hashes are the same or 0.
    Hi Brandon,

    I do appreciate the reply.

    I'm not entirely sure if this is what you had in mind however:

    I've been using this code to traverse the vertex data. The "value" variable can be incremented and decremented at runtime with key presses. For each of the rocks, we then hash the data at "pVoid + value" with size "sizeof(unsigned int)". The hashed value is displayed above the corresponding rocks using D3DTextF().

    Using this method, I have been able to identify the rotation of the rock models however the vertex structure in use does not appear to contain any color information. (As far as I can see!)

    C++ Code:
    //Prototype of crc32()
    DWORD crc32(unsigned char* data, unsigned DWORD length);

    DWORD value = 0;
    HRESULT WINAPI hkDrawIndexedPrimitive(LPDIRECT3DDEVICE9 pDevice, D3DPRIMITIVETYPE Type, int BaseVertexIndex, UINT MinIndex, UINT NumVertices, UINT StartIndex, UINT PrimitiveCount)
    {
        //Calculate IDs etc (Omitted for clarity)
        ...
       
        //Increment/decrement value when keys are pressed
        ...
       
        //5308636 and 5767341 are the rock ore primitives.
        if (ID == 5308636 || ID == 5767341)
        {
            IDirect3DVertexBuffer9* vertexBuffer;
            UINT offset;
            UINT stride;
           
            if (pDevice->GetStreamSource(0, &vertexBuffer, &offset, &stride) == D3D_OK)
            {
                void* pVoid;
               
                D3DVERTEXBUFFER_DESC desc;
                vertexBuffer->GetDesc(&desc);
               
                vertexBuffer->Lock(StartIndex, value + sizeof(unsigned int), (void**)&pVoid, 0);
               
                DWORD crc = crc32((BYTE*)pVoid + value, sizeof(unsigned int));
                D3DTextF(D3DCOLOR_XRGB(0, 255, 0), x, y, "%lu", crc);
               
                vertexBuffer->Unlock();
            }
        }
       
        return oDrawIndexedPrimitive(pDevice, Type, BaseVertexIndex, MinIndex, NumVertices, StartIndex, PrimitiveCount);
    }

    With regard to the textures, I have not attempted to create a proxy class such as your IDirect3DBaseTexture9Proxy from the Genevieve project however I may pursue that next if it seems like the way to go.

    C++ Code:
    //Prototype of crc32()
    DWORD crc32(unsigned char* data, unsigned DWORD length);

    DWORD value = 0;
    HRESULT WINAPI hkDrawIndexedPrimitive(LPDIRECT3DDEVICE9 pDevice, D3DPRIMITIVETYPE Type, int BaseVertexIndex, UINT MinIndex, UINT NumVertices, UINT StartIndex, UINT PrimitiveCount)
    {
        //Calculate IDs etc (Omitted for clarity)
        ...
       
        //Increment/decrement value when keys are pressed
        ...
       
        //5308636 and 5767341 are the rock ore primitives.
        if (ID == 5308636 || ID == 5767341)
        {
            IDirect3DBaseTexture9* baseTexture;
            pDevice->GetTexture(0, &baseTexture);
           
            IDirect3DTexture9* texture = (IDirect3DTexture9*)baseTexture;
            D3DLOCKED_RECT lockedRect;
           
            if (texture->LockRect(0, &lockedRect, NULL, D3DLOCK_READONLY) == D3D_OK)
            {
                DWORD *pData = (DWORD*)lockedRect.pBits;

                D3DSURFACE_DESC desc;
                texture->GetLevelDesc(0, &desc);

                DWORD crc = crc32((BYTE*)pData, value);
                //DWORD crc = crc32((BYTE*)pData + value, 4);

                D3DTextF(D3DCOLOR_XRGB(0, 255, 0), x, y, "%lu", crc);
            }
           
            texture->UnlockRect(0);
        }
       
        return oDrawIndexedPrimitive(pDevice, Type, BaseVertexIndex, MinIndex, NumVertices, StartIndex, PrimitiveCount);
    }

    Using various mutations of the above code, each rock has the same texture hash, however other textures such as ground textures have different hashes. Again, the "value" variable is incremented and decremented at runtime to explore the data.
    Last edited by Kimon; 05-09-2015 at 04:21 PM.

  8. #8
    Join Date
    Feb 2011
    Location
    The Future.
    Posts
    5,600
    Mentioned
    396 Post(s)
    Quoted
    1598 Post(s)

    Default

    Quote Originally Posted by Kimon View Post
    ...

    Your code now exhibits undefined behaviour. There was a time when they used interleaved structures (which is why I suggested that) and they still do in OpenGL but it seems in Direct-X, ALL strides are "12" (X, Y, Z) * (sizeof(float)). It wasn't always this way (tightly packed).

    So you're right, they're rendering their textures another way. I'll have to look into it to see how.


    As for why your code is undefined behaviour? pDevice->GetTexture(0, &tex) returns a texture of size 1 x 1. Calculating a CRC32 hash on anything except that ONE pixel is undefined. So if you're "increasing value", you're causing UB.

    Using the texture wrapper from the github, you can save the width and height of the texture upon creation and it turns out to be 21 x 3.

    However, ALL the textures point to the same memory location: http://i.imgur.com/trg7pjk.png

    The 1 x 1 texture is just an alpha texture to tell the graphics card to render everything with a white tint (0xFFFFFFFF).

    If you change the texture, everything will render to whatever texture you apply (purple in my post).


    Basically, model hooks are a lot easier now, but texture hooks are harder and require more debugging of the client.


    Animated textures are rendered with "DrawPrimitive" you can hook that and see the sparkle on the rock ID.
    Models ONLY are rendered with "DrawIndexedPrimitive" you can hook that for models and do a hash on the vertices.

    For regular textures, I have to look into it.
    Last edited by Brandon; 05-09-2015 at 08:51 PM.
    I am Ggzz..
    Hackintosher

  9. #9
    Join Date
    May 2015
    Posts
    11
    Mentioned
    0 Post(s)
    Quoted
    9 Post(s)

    Default

    Quote Originally Posted by Brandon View Post
    Your code now exhibits undefined behaviour. There was a time when they used interleaved structures (which is why I suggested that) and they still do in OpenGL but it seems in Direct-X, ALL strides are "12" (X, Y, Z) * (sizeof(float)). It wasn't always this way (tightly packed).

    So you're right, they're rendering their textures another way. I'll have to look into it to see how.


    As for why your code is undefined behaviour? pDevice->GetTexture(0, &tex) returns a texture of size 1 x 1. Calculating a CRC32 hash on anything except that ONE pixel is undefined. So if you're "increasing value", you're causing UB.

    Using the texture wrapper from the github, you can save the width and height of the texture upon creation and it turns out to be 21 x 3.

    However, ALL the textures point to the same memory location: (url)

    The 1 x 1 texture is just an alpha texture to tell the graphics card to render everything with a white tint (0xFFFFFFFF).

    If you change the texture, everything will render to whatever texture you apply (purple in my post).


    Basically, model hooks are a lot easier now, but texture hooks are harder and require more debugging of the client.


    Animated textures are rendered with "DrawPrimitive" you can hook that and see the sparkle on the rock ID.
    Models ONLY are rendered with "DrawIndexedPrimitive" you can hook that for models and do a hash on the vertices.

    For regular textures, I have to look into it.
    This is very interesting stuff!

    Here's what I was talking about earlier, and indeed, evidence of what you've said above. Notice that the Iron ore appears to be almost a purple color, while a noticeably different color is applied to the Copper rocks.

    After applying a pink texture:
    rocks.png
    (Click to enlarge)

    And here's the code used to produce this:
    C++ Code:
    HRESULT WINAPI hkDrawIndexedPrimitive(LPDIRECT3DDEVICE9 pDevice, D3DPRIMITIVETYPE Type, int BaseVertexIndex, UINT MinIndex, UINT NumVertices, UINT StartIndex, UINT PrimitiveCount)
    {
        //5308636 and 5767341 are the rock ore primitives.
        if (ID == 5308636 || ID == 5767341)
        {
            LPDIRECT3DTEXTURE9 pinkTexture;

            const BYTE bPink[58] =
            {
                0x42, 0x4D, 0x3A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x36, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
                0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
                0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x80, 0x00, 0xFF, 0x00
            };

            D3DXCreateTextureFromFileInMemory(pDevice, (LPCVOID)&bPink, 58, &pinkTexture);
            pDevice->SetTexture(0, pinkTexture);
        }
       
        return oDrawIndexedPrimitive(pDevice, Type, BaseVertexIndex, MinIndex, NumVertices, StartIndex, PrimitiveCount);
    }

  10. #10
    Join Date
    Feb 2011
    Location
    The Future.
    Posts
    5,600
    Mentioned
    396 Post(s)
    Quoted
    1598 Post(s)

    Default

    Quote Originally Posted by Kimon View Post
    ...

    Yup. That's what I meant. It's a tint over the entire client. Notice how all the RED ID's below are the same texture ID.

    I wrote the ID generation for textures just now to see if ALL textures would show up but it seems models are being applied a module texture which cannot be locked (button says OpenGL but it's direct-x, SRL loads both plugins):




    I'll figure it out soon but this is one step closer than I was a couple hours ago (these are all TEXTURE IDs [CRC32].. not model IDs). I believe model textures might have to have their ID's generated on start and may render with a shader rather than SetTexture.


    Green ones are regular textures of type: D3DRTYPE_TEXTURE, red ones seem to be materials or volumetric or some other type of texture.. white ones are textures used in animations (sparkles on the rocks).

    More debugging is required to see what calls are being made for model textures.

    My logs look like:

    Code:
    SetTexture
    DrawIndexedPrimitive
    SetTexture
    SetSamplerState
    SetSamplerState
    DrawIndexedPrimitive
    SetTexture
    SetSamplerState
    SetSamplerState
    DrawIndexedPrimitive
    SetTexture
    DrawIndexedPrimitive
    SetTexture
    DrawIndexedPrimitive
    
    
    SetTexture
    DrawIndexedPrimitive
    TestCooperativeLevel
    SetDepthStencilSurface
    SetStreamSource
    SetTexture
    SetIndices
    Last edited by Brandon; 05-10-2015 at 01:43 AM.
    I am Ggzz..
    Hackintosher

  11. #11
    Join Date
    May 2015
    Posts
    11
    Mentioned
    0 Post(s)
    Quoted
    9 Post(s)

    Default

    Quote Originally Posted by Brandon View Post
    ...
    Materials appeared to be somewhat of a dead end. Assuming that I have correctly hooked SetMaterial, it would seem that the function is never called.

    I do wonder if the developers have come to this arrangement to deter our efforts, or indeed, if there is some other productive explanation.
    Last edited by Kimon; 05-10-2015 at 03:29 AM.

  12. #12
    Join Date
    Feb 2011
    Location
    The Future.
    Posts
    5,600
    Mentioned
    396 Post(s)
    Quoted
    1598 Post(s)

    Default

    Quote Originally Posted by Kimon View Post
    ..
    They are doing:

    C++ Code:
    IDirect3DDevice9_SetStreamSource(00000000, 3F2EA3A0, 00000000, 0000000C)
    IDirect3DDevice9_SetStreamSource(00000001, 3D850240, 00000000, 00000004)
    IDirect3DDevice9_SetStreamSource(00000002, 3D850680, 00000000, 00000008)
    IDirect3DDevice9_SetIndices(2B166B00)
    IDirect3DDevice9_SetStreamSource(00000003, 3D8515A0, 00000000, 0000000C)
    IDirect3DDevice9_SetTexture(00000000, 3123DEE0)
    IDirect3DDevice9_SetSamplerState(00000000, 00000002, 00000003)
    IDirect3DDevice9_SetVertexShaderConstantF(00000000, 306C2020, 0000000C)
    IDirect3DDevice9_SetPixelShaderConstantF(00000000, 306C2020, 00000005)
    IDirect3DDevice9_DrawIndexedPrimitive(00000004, 00000000, 00000000, 00000082, 00000000, 0000004E)

    .
    .
    .

    IDirect3DDevice9_SetTexture(00000000, 3D8D4880)
    IDirect3DDevice9_SetStreamSource(00000000, 31B573A0, 00000000, 00000020)
    IDirect3DDevice9_SetVertexDeclaration(310440A0)
    IDirect3DDevice9_SetVertexShaderConstantF(00000000, 306C2020, 00000006)
    IDirect3DDevice9_SetPixelShaderConstantF(00000000, 306C2020, 00000001)
    IDirect3DDevice9_DrawPrimitive(00000006, 00000000, 00000002)


    So yeah.. they are rendering the texture but using a shader to do it now. If you call pDevice->SetVertexShader(nullptr), you will notice that -- that one section of the model that contains the ore is "hollow".

    You can disassemble the shader and see what parameters they are passing to it. Grab the colour(s) from the shader stream source.

    Take note of the stream numbers: 0, 1, 2, 3.
    3-4 streams in use at any given time. The same thing is done in OpenGL except they interleave it.
    Last edited by Brandon; 05-10-2015 at 04:53 AM.
    I am Ggzz..
    Hackintosher

  13. #13
    Join Date
    Jun 2007
    Location
    The land of the long white cloud.
    Posts
    3,702
    Mentioned
    261 Post(s)
    Quoted
    2006 Post(s)

  14. #14
    Join Date
    May 2015
    Posts
    11
    Mentioned
    0 Post(s)
    Quoted
    9 Post(s)

    Default

    Quote Originally Posted by Brandon View Post
    You can disassemble the shader and see what parameters they are passing to it. Grab the colour(s) from the shader stream source.

    Take note of the stream numbers: 0, 1, 2, 3.
    3-4 streams in use at any given time. The same thing is done in OpenGL except they interleave it.
    Here's a dump of the shader from pDevice->GetVertexShader() at the time of the DrawIndexedPrimitive call:

    Code:
    //
    // Generated by Microsoft (R) HLSL Shader Compiler 9.27.952.3022
    //
    // Parameters:
    //
    //   float3 AmbientColour;
    //   float3 AntiSunColour;
    //   float4 DistanceFogPlane;
    //   float3 EyePos;
    //   float4 HeightFogPlane;
    //   float3 SunColour;
    //   float3 SunDir;
    //   float4x2 TexCoordMatrix;
    //   float4x4 WVPMatrix;
    //
    //
    // Registers:
    //
    //   Name             Reg   Size
    //   ---------------- ----- ----
    //   WVPMatrix        c0       4
    //   TexCoordMatrix   c4       2
    //   EyePos           c6       1
    //   DistanceFogPlane c7       1
    //   HeightFogPlane   c8       1
    //   SunDir           c9       1
    //   SunColour        c10      1
    //   AntiSunColour    c11      1
    //   AmbientColour    c12      1
    //
    
        vs_2_0
        def c13, 0, 1, 0, 0
        dcl_position v0
        dcl_texcoord v1
        dcl_normal v2
        dcl_color v3
        dp4 oPos.x, v0, c0
        dp4 oPos.y, v0, c1
        dp4 oPos.z, v0, c2
        dp4 oPos.w, v0, c3
        dp4 oT0.x, v1, c4
        dp4 oT0.y, v1, c5
        dp3 r0.x, v2, c9
        max r0.y, r0.x, c13.x
        max r0.x, -r0.x, c13.x
        min r0.xy, r0, c13.y
        mov r1.xyz, c10
        mad r0.yzw, r0.y, r1.xxyz, c12.xxyz
        mad oT2.xyz, r0.x, c11, r0.yzww
        add r0.xyz, -v0, c6
        dp3 r0.w, r0, r0
        rsq r0.w, r0.w
        mul oT1.xyz, r0.w, r0
        dp4 r0.x, v0, c8
        max r0.x, r0.x, c13.x
        min oT4.x, r0.x, c13.y
        dp4 r0.x, v0, c7
        max r0.x, r0.x, c13.x
        min oT4.y, r0.x, c13.y
        mov oD0, v3
        mov oT0.zw, c13.x
        mov oT3.xyz, v2
        mov oT5, c13.x
        mov oT6.xyz, c13.x
        mov oT7, c13.x
    
    // approximately 29 instruction slots used
    I would assume out of that, "float3 AmbientColour" (C12) is the primary point of interest. However I'm not entirely sure how to read from the "shader stream source", are calls to SetStreamSource used to set the stream source for shaders as well as vertex buffers? My knowledge of DirectX is somewhat limited haha

    From reading around, the most likely function seemed to be IDirect3DVertexShader9::GetFunction which "gets a pointer to the shader data" as shown here: https://msdn.microsoft.com/en-us/lib...=vs.85%29.aspx

    I also found this: "Stream-output data can be read by programmable shaders using load functions (such as Load)."
    Here: https://msdn.microsoft.com/en-us/lib...=vs.85%29.aspx

    Which could possibly be somewhere along the right lines?
    Last edited by Kimon; 05-10-2015 at 02:19 PM.

  15. #15
    Join Date
    Feb 2011
    Location
    The Future.
    Posts
    5,600
    Mentioned
    396 Post(s)
    Quoted
    1598 Post(s)

    Default

    Quote Originally Posted by Kimon View Post
    Which could possibly be somewhere along the right lines?
    Sorry for the late reply.


    Mat4 wvp;
    pDevice->GetVertexShaderConstantF(0, reinterpret_cast<float*>(&wvp), 4);

    In the above, we are accessing register C0 for the WorldViewMatrix. It is of size 4 and is a float4x4 matrix.

    That's all there is to it. If you wanted to access the data BEFORE the vertex shader gets it, just hook SetStreamSource and iterate it pulling out whatever you need from it OR call GetStreamSource(StreamNumber, &vbo) in DrawIndexedPrimitive.

    There are 3 or 4 streams in use at any given time. If I had to guess, stream 1 is the colours of every vertex of the model. I made this assumption based on the stride for stream 1.

    C++ Code:
    IDirect3DDevice9_SetStreamSource(00000001, 3D850240, 00000000, 00000004)

    The stride is 4 and stream number is 1. A colour consists of 4 components (ARGB).

    Stream 2 is texCoords or Normals (most likely normals [U, V]).

    C++ Code:
    IDirect3DDevice9_SetStreamSource(00000002, 3D850680, 00000000, 00000008)

    I made this assumption based on its stride as well. The stride is 8: X, Y -- where both are float -- 4 bytes each.

    Finally, Stream 0 or 3 is the vertices (stride of 12 -- X, Y, Z -- where all are float -- 4 bytes each).


    I don't have time to test all of this atm, but I'm fairly confident, this is the case. I will test it during the week.
    Last edited by Brandon; 05-11-2015 at 12:42 AM.
    I am Ggzz..
    Hackintosher

  16. #16
    Join Date
    May 2015
    Posts
    11
    Mentioned
    0 Post(s)
    Quoted
    9 Post(s)

    Default

    Quote Originally Posted by Brandon View Post
    Sorry for the late reply.

    Mat4 wvp;
    pDevice->GetVertexShaderConstantF(0, reinterpret_cast<float*>(&wvp), 4);

    In the above, we are accessing register C0 for the WorldViewMatrix. It is of size 4 and is a float4x4 matrix.

    That's all there is to it. If you wanted to access the data BEFORE the vertex shader gets it, just hook SetStreamSource and iterate it pulling out whatever you need from it OR call GetStreamSource(StreamNumber, &vbo) in DrawIndexedPrimitive.

    There are 3 or 4 streams in use at any given time. If I had to guess, stream 1 is the colours of every vertex of the model. I made this assumption based on the stride for stream 1.

    C++ Code:
    IDirect3DDevice9_SetStreamSource(00000001, 3D850240, 00000000, 00000004)

    The stride is 4 and stream number is 1. A colour consists of 4 components (ARGB).

    Stream 2 is texCoords or Normals (most likely normals [U, V]).

    C++ Code:
    IDirect3DDevice9_SetStreamSource(00000002, 3D850680, 00000000, 00000008)

    I made this assumption based on its stride as well. The stride is 8: X, Y -- where both are float -- 4 bytes each.

    Finally, Stream 0 or 3 is the vertices (stride of 12 -- X, Y, Z -- where all are float -- 4 bytes each).


    I don't have time to test all of this atm, but I'm fairly confident, this is the case. I will test it during the week.
    Thanks Brandon, very useful information as always.

    I've used GetPixelShaderConstantF to retrieve the coordinates of the model which can then be transformed to produce normalized device coordinates, thus allowing the IDs to be drawn on the screen etc. I didn't have any luck using GetPixelShaderConstantF for anything color related though, so I turned to the stream source.

    So far, I have only focused on stream 1, which as you said, has the tell-tail stride of 4.

    This code:
    C++ Code:
    HRESULT WINAPI hkDrawIndexedPrimitive(LPDIRECT3DDEVICE9 pDevice, D3DPRIMITIVETYPE Type, int BaseVertexIndex, UINT MinIndex, UINT NumVertices, UINT StartIndex, UINT PrimitiveCount)
    {
        //Calculate IDs etc (Omitted for clarity)
        ...
       
        //Increment/decrement value when keys are pressed
        ...
       
        //5308636 and 5767341 are the rock ore primitives.
        if (ID == 5308636 || ID == 5767341)
        {
            IDirect3DVertexBuffer9* vertexBuffer;
            UINT offset;
            UINT stride;

            if (pDevice->GetStreamSource(1, &vertexBuffer, &offset, &stride) == D3D_OK)
            {
                char* pVerts;
               
                //I've locked the entire stream for now to avoid potential mistakes with offsets and lengths
                vertexBuffer->Lock(0, 0, (void**)&pVerts, D3DLOCK_READONLY);

                D3DXCOLOR color = *reinterpret_cast<D3DXCOLOR*>(&pVerts[(stride * value) + offset]);
               
                DrawTextF(D3DCOLOR_XRGB(0, 255, 0), x, y, "%f, %f, %f, %f", color.r, color.g, color.b, color.a);

                vertexBuffer->Unlock();
            }
        }
       
        return oDrawIndexedPrimitive(pDevice, Type, BaseVertexIndex, MinIndex, NumVertices, StartIndex, PrimitiveCount);
    }

    Results in this:


    So it's safe to say I've gone wrong somewhere lmao

    I haven't had a chance to approach the problem from the perspective of SetStreamSource (hooked) as I'm hooking quite late, after the client loads. If I have time, I'll probably persevere with the above code and indeed, look into wrapping IDirect3DDevice9 with hope of hooking SetStreamSource thereafter.

    Thanks again!

  17. #17
    Join Date
    Mar 2007
    Posts
    3,042
    Mentioned
    1 Post(s)
    Quoted
    14 Post(s)

    Default

    Quote Originally Posted by Brandon View Post
    Sorry for the late reply.


    Mat4 wvp;
    pDevice->GetVertexShaderConstantF(0, reinterpret_cast<float*>(&wvp), 4);

    In the above, we are accessing register C0 for the WorldViewMatrix. It is of size 4 and is a float4x4 matrix.

    That's all there is to it. If you wanted to access the data BEFORE the vertex shader gets it, just hook SetStreamSource and iterate it pulling out whatever you need from it OR call GetStreamSource(StreamNumber, &vbo) in DrawIndexedPrimitive.

    There are 3 or 4 streams in use at any given time. If I had to guess, stream 1 is the colours of every vertex of the model. I made this assumption based on the stride for stream 1.

    C++ Code:
    IDirect3DDevice9_SetStreamSource(00000001, 3D850240, 00000000, 00000004)

    The stride is 4 and stream number is 1. A colour consists of 4 components (ARGB).

    Stream 2 is texCoords or Normals (most likely normals [U, V]).

    C++ Code:
    IDirect3DDevice9_SetStreamSource(00000002, 3D850680, 00000000, 00000008)

    I made this assumption based on its stride as well. The stride is 8: X, Y -- where both are float -- 4 bytes each.

    Finally, Stream 0 or 3 is the vertices (stride of 12 -- X, Y, Z -- where all are float -- 4 bytes each).


    I don't have time to test all of this atm, but I'm fairly confident, this is the case. I will test it during the week.
    If it's still the same as it was for client build #666 , then you're pretty much spot on. Stream 0 is positions, 1 is colors, 2 is texcoords, and 3 (if present) is normals.
    :-)

  18. #18
    Join Date
    Feb 2011
    Location
    The Future.
    Posts
    5,600
    Mentioned
    396 Post(s)
    Quoted
    1598 Post(s)

    Default

    Quote Originally Posted by Method View Post
    If it's still the same as it was for client build #666 , then you're pretty much spot on. Stream 0 is positions, 1 is colors, 2 is texcoords, and 3 (if present) is normals.

    Perfect! This is good news. Thanks a lot! I will have to test whether its the same though (maybe on the weekend).


    Quote Originally Posted by Kimon View Post
    ...
    Try:

    C++ Code:
    std::uint32_t GetColour(std::uint8_t *colours, std::int16_t index, std::uint16_t stride)
    {
        std::uint32_t res = 0;
        memcpy(&res, &colours[index * stride], sizeof(std::uint32_t));
        return res;
    }


    HRESULT IDirect3DDevice9Proxy::DrawIndexedPrimitive(D3DPRIMITIVETYPE PrimitiveType, INT BaseVertexIndex, UINT MinVertexIndex, UINT NumVertices, UINT startIndex, UINT primCount)
    {
        //Get stream 1 (VBO) & its IBO.
        //pDevice->GetIndices(&ibo);

        std::uint8_t *colours = NULL;
        std::uint16_t *indices = NULL;
        UINT EndIndex = startIndex + (primCount * 3);

        VertexBuffer->Lock(0, 0, reinterpret_cast<void **>(&colours), 0);
        IndexBuffer->Lock(0, primCount * 3 * sizeof(std::uint16_t), reinterpret_cast<void **>(&indices), 0);

        for (UINT I = startIndex; I < EndIndex; ++I)
        {
            std::uint32_t colour = GetColour(colours, indices[I] + BaseVertexIndex, Stride);
        }

        IndexBuffer->Unlock();
        VertexBuffer->Unlock();


        return pDevice->DrawIndexedPrimitive(PrimitiveType, BaseVertexIndex, MinVertexIndex, NumVertices, startIndex, primCount);
    }


    You may or may not need the index buffer. Again, I have to test but I only get weekends off from work so.. you can mess around with it and report back.

    Also, the colour is NOT a float. I said: ARGB which if the stride is four, becomes an unsigned integer. If the stride was 16, then EACH component of the ARGB colour would be a float. However, that's not the case. I might have been confusing in my previous post since I rushed to type it out but hopefully this clears things up.

    To split the unsigned integer representation into its components, you can use a union:

    C++ Code:
    typedef union
    {
        std::uint8_t A, R, G, B;
        std::uint32_t Colour;
    } ARGB;

    std::uint8_t R = reinterpret_cast<ARGB*>(&your_colour_here)->R;
    std::uint8_t G = reinterpret_cast<ARGB*>(&your_colour_here)->G;
    std::uint8_t B = reinterpret_cast<ARGB*>(&your_colour_here)->B;


    //OR:

    ARGB col = {0};
    col.Colour = your_colour_here;

    std::uint8_t R = col.R;
    std::uint8_t G = col.G;
    std::uint8_t B = col.B;
    Last edited by Brandon; 05-11-2015 at 01:57 PM.
    I am Ggzz..
    Hackintosher

  19. #19
    Join Date
    May 2015
    Posts
    11
    Mentioned
    0 Post(s)
    Quoted
    9 Post(s)

    Default

    Quote Originally Posted by Brandon View Post
    ...
    [/Highlight]


    I don't think there's too much more to be said really! lmao

    There appears to be a slight color shift/randomization between logins. It was fairly trivial to get around by searching the vertice colors with a tolerance (+/- 2 seems to be sufficient). In reality, we only need to determine the color of the model once so this seems like a great solution.

  20. #20
    Join Date
    Jun 2007
    Location
    The land of the long white cloud.
    Posts
    3,702
    Mentioned
    261 Post(s)
    Quoted
    2006 Post(s)

    Default

    Quote Originally Posted by Kimon View Post


    I don't think there's too much more to be said really! lmao

    There appears to be a slight color shift/randomization between logins. It was fairly trivial to get around by searching the vertice colors with a tolerance (+/- 2 seems to be sufficient). In reality, we only need to determine the color of the model once so this seems like a great solution.
    That is the coolest thing I have seen 2k15! What are you planning to do from here?

  21. #21
    Join Date
    May 2015
    Posts
    11
    Mentioned
    0 Post(s)
    Quoted
    9 Post(s)

    Default

    Quote Originally Posted by The Mayor View Post
    That is the coolest thing I have seen 2k15! What are you planning to do from here?
    Hopefully build a functional bot from the ground up.

    I've always been concerned that known bot clients could easily be detected, or at least draw some attention if known fixed parameters such as the client's resolution became known. I haven't used SMART for a good few years now, I could have sworn at one point the resolution was fixed. (Maybe it still is?) This is probably just paranoia but anything we can do to blend in has to be good haha

    I'm not sure if this approach has been taken before, however I've been building upon the RuneScape client source (which you can find here). As far as clients go, I don't think we can get any closer to "the real thing" than this.

    Now that we have a way to detect the models, their position and their variants, I'll probably look into navigation and eventually other requirements such as mouse hooks. There's an interesting texture that seems to display a large area around you:

    This could hopefully be used to pinpoint your current world position. If there seems to be a lack of less expensive options, we could initially locate this sub-section of the map (using an image of the full map). Thereafter, we would most likely keep track of movement using the player's surroundings.

    A few years back, I had a look into HAAR training to track models using OpenCV. It turned out to be semi-reliable, but too expensive for use within a finished bot. I dare say template matching with OpenCV could be used to establish the player's location (initially).

    Perhaps there's a much better alternative, some information that is accessible via DirectX.

    And so it begins!

  22. #22
    Join Date
    Feb 2011
    Location
    The Future.
    Posts
    5,600
    Mentioned
    396 Post(s)
    Quoted
    1598 Post(s)

    Default

    Quote Originally Posted by Kimon View Post
    I don't think there's too much more to be said really! lmao


    :O Was I right? OR??

    Btw (just a "suggestion"), to calculate things once, use a wrapper. I say this because for textures, instead of calling "GetTexture" every single time and doing a hash on it in DrawIndexedPrimitive, I wrote a wrapper for it and I give it to the client. When the client calls "Unlock", I hash the texture and store its ID.

    This is only done when the texture is created by the client OR modified. That way, every frame (DrawIndexedPrimitive), you can just do:

    pDevice->GetTexture(....)->GetHash();

    Did the same thing for models and it works brilliantly. 50-FPS.
    Last edited by Brandon; 05-11-2015 at 06:16 PM.
    I am Ggzz..
    Hackintosher

  23. #23
    Join Date
    May 2015
    Posts
    11
    Mentioned
    0 Post(s)
    Quoted
    9 Post(s)

    Default

    Quote Originally Posted by Brandon View Post
    :O Was I right? OR??
    You were spot on!

    It's a shame there's some randomisation at play. We could otherwise produce a simple hash but the color search works just as well. I haven't encountered any issues with the accuracy.

  24. #24
    Join Date
    Jun 2007
    Location
    The land of the long white cloud.
    Posts
    3,702
    Mentioned
    261 Post(s)
    Quoted
    2006 Post(s)

  25. #25
    Join Date
    May 2012
    Posts
    499
    Mentioned
    23 Post(s)
    Quoted
    228 Post(s)

    Default

    Quote Originally Posted by Brandon View Post
    Did the same thing for models and it works brilliantly. 50-FPS.
    Do you have any ETA on a directx plugin?
    Having allot of trouble with the FPS drop after a few hours within OGL..

Page 1 of 2 12 LastLast

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •