Question about NetworkStreamSendSpecial

05/20/2021 05:56 ozuromo#1
I'm trying to do a wait hack, and to do that i'm trying to use NetworkStreamSendSpecial, but when I try to use it nothing happens.

I have the address of NetworkStreamSendSpecial function, of NetworkStream instance and of NetworkStreamSendSequence, and I'm using the following code:
Code:
    TPacketCGAttack kPacketAtk;
    kPacketAtk.header = 0x52;
    kPacketAtk.bType = 0;
    kPacketAtk.dwVictimVID = mobVid;
    NetSendSpecial((void*)netInstance, sizeof(kPacketAtk), &kPacketAtk)
    NetSendSequence((void*)netInstance);
I know the address is right because if I use NetworkStreamSendSpecial and don't use NetworkStreamSendSequence I get disconnected. And I know 0x52 is the correct header. Any tips about why nothing happens?
05/20/2021 08:28 HelloBrightness#2
more informations would be nice, some disassembly to understand *why* u know that the header 0x52 is correct, since its usualy the header 2 instead. more code to understand how you get the mobVid or verify if its correct or not.
05/20/2021 22:53 ozuromo#3
Ok. So this is NetworkStream::SendAttackPacket assembly:
[Only registered and activated users can see links. Click Here To Register...]
In the end of this function we have:
[Only registered and activated users can see links. Click Here To Register...]
The complete code I use to try to simulate this, is:
Code:
struct TPacketCGAttack
{
    BYTE	header;
    BYTE	bType;
    DWORD	dwVictimVID;
};
typedef bool(__thiscall* typeNetSendSpecial)(void* This, int nLen, void* pvBuf);
typedef bool(__thiscall* typeNetSendSequence)(void* This);
typeNetSendSpecial NetSendSpecial = (typeNetSendSpecial)(baseAddress + 0x1EB5E0);
typeNetSendSequence NetSendSequence = (typeNetSendSequence)(baseAddress + 0x2A5240);
TPacketCGAttack kPacketAtk;
kPacketAtk.header = 0x52;
kPacketAtk.bType = 0;
kPacketAtk.dwVictimVID = dwVID;
NetSendSpecial((void*)netInstance, sizeof(kPacketAtk), &kPacketAtk);
NetSendSequence((void*)netInstance);
I get the dwVID by using GetTargetVid, and I know it's right because if I use it in SendAttackPacket it works. The reason why I'm trying to use SendSpecial is to see if it works better.

When I execute this code nothing happens! If I don't call SendSequence or change the Header I get instantly disconnected. I tried using the analogous function for Archers, which is AddFlyTargetingPacket and SendShootPacket, and the same thing happens, I don't give any damage but the arrows disappear from my inventory...
05/21/2021 15:23 MrCrisp#4
Either, it is fixed on your server, or you are too far away from the monster. Try it on a metin stone or a mob that is really close to you.
05/21/2021 18:00 HelloBrightness#5
Quote:
Originally Posted by ozuromo View Post
Ok. So this is NetworkStream::SendAttackPacket assembly:
[Only registered and activated users can see links. Click Here To Register...]
In the end of this function we have:
[Only registered and activated users can see links. Click Here To Register...]
The complete code I use to try to simulate this, is:
Code:
struct TPacketCGAttack
{
    BYTE	header;
    BYTE	bType;
    DWORD	dwVictimVID;
};
typedef bool(__thiscall* typeNetSendSpecial)(void* This, int nLen, void* pvBuf);
typedef bool(__thiscall* typeNetSendSequence)(void* This);
typeNetSendSpecial NetSendSpecial = (typeNetSendSpecial)(baseAddress + 0x1EB5E0);
typeNetSendSequence NetSendSequence = (typeNetSendSequence)(baseAddress + 0x2A5240);
TPacketCGAttack kPacketAtk;
kPacketAtk.header = 0x52;
kPacketAtk.bType = 0;
kPacketAtk.dwVictimVID = dwVID;
NetSendSpecial((void*)netInstance, sizeof(kPacketAtk), &kPacketAtk);
NetSendSequence((void*)netInstance);
I get the dwVID by using GetTargetVid, and I know it's right because if I use it in SendAttackPacket it works. The reason why I'm trying to use SendSpecial is to see if it works better.

When I execute this code nothing happens! If I don't call SendSequence or change the Header I get instantly disconnected. I tried using the analogous function for Archers, which is AddFlyTargetingPacket and SendShootPacket, and the same thing happens, I don't give any damage but the arrows disappear from my inventory...
Thanks for the Informations, you're using the wrong struct. You can see it in the disassembly. You accessing ebp-08 for for the Header (first byte, 8-1 total = 7 left), ebp-7 for the type (second byte, 8-1-1 total = 6 left total), ebp-6 for the dword/vid (first dowrd, 8-1-1-4 = 2 left total) - you have to append these missing two bytes.

You could've noticed this sooner, you wrote yourself
"8 push sizeof(kPacket) to the stack"
Code:
struct TPacketCGAttack
{
    BYTE	header;//1
    BYTE	bType;//2
    DWORD	dwVictimVID;//6
};
is to small
05/21/2021 22:26 ozuromo#6
Quote:
Originally Posted by HelloBrightness View Post
Thanks for the Informations, you're using the wrong struct. You can see it in the disassembly. You accessing ebp-08 for for the Header (first byte, 8-1 total = 7 left), ebp-7 for the type (second byte, 8-1-1 total = 6 left total), ebp-6 for the dword/vid (first dowrd, 8-1-1-4 = 2 left total) - you have to append these missing two bytes.

You could've noticed this sooner, you wrote yourself
"8 push sizeof(kPacket) to the stack"
Code:
struct TPacketCGAttack
{
    BYTE	header;//1
    BYTE	bType;//2
    DWORD	dwVictimVID;//6
};
is to small
It's no that, if you do sizeof(TPacketCGAttack) you will get 8. And if I use 2 more bytes I get disconnected too.

Quote:
Originally Posted by MrCrisp View Post
Either, it is fixed on your server, or you are too far away from the monster. Try it on a metin stone or a mob that is really close to you.
I can identify if it is fixed looking into the assembly? What should I look for?
05/21/2021 23:28 HelloBrightness#7
Quote:
Originally Posted by ozuromo View Post
It's no that, if you do sizeof(TPacketCGAttack) you will get 8. And if I use 2 more bytes I get disconnected too.
Code:
#include <stdio.h>
int main()
{
    struct TPacketCGAttack_B { //size of BYTE
        unsigned char test;
    };
    
    struct TPacketCGAttack_D { //size of DWORD
        unsigned int test;
    };
    
    
    struct TPacketCGAttack1 { //only one BYTE
        unsigned char header;
    };
    
    struct TPacketCGAttack2 { //adding one BYTE, having two BYTES
        unsigned char header;
        unsigned char bType;
    };
    
    struct TPacketCGAttack3 { //adding four BYTES aka. a DWORD, having 6 BYTES
        unsigned char header;
        unsigned char bType;
        unsigned int dwVictimVID;
    };
    
    
    printf("TPacketCGAttack_B: %ld\nTPacketCGAttack_D: %ld\nTPacketCGAttack1: %ld\nTPacketCGAttack2: %ld\nTPacketCGAttack3: %ld", sizeof(TPacketCGAttack_B), sizeof(TPacketCGAttack_D), sizeof(TPacketCGAttack1), sizeof(TPacketCGAttack2), sizeof(TPacketCGAttack3));

    return 0;
}
OUTPUT:
TPacketCGAttack_B: 1
TPacketCGAttack_D: 4
TPacketCGAttack1: 1
TPacketCGAttack2: 2
TPacketCGAttack3: 8
05/21/2021 23:49 MrCrisp#8
Quote:
Originally Posted by ozuromo View Post
It's no that, if you do sizeof(TPacketCGAttack) you will get 8. And if I use 2 more bytes I get disconnected too.
Make sure you align the structs correctly! They have to be aligned by a byte, not by 4 bytes. See the pragma pack operator for further details.
05/22/2021 01:24 ozuromo#9
Quote:
Originally Posted by MrCrisp View Post
Make sure you align the structs correctly! They have to be aligned by a byte, not by 4 bytes. See the pragma pack operator for further details.
Yep, that was the problem! Thanks a lot, would never thing of that.

Code:
#pragma pack(pop)
#pragma pack(push, 1)
struct  TPacketCGAttack
{
    BYTE	header;
    BYTE	bType;
    DWORD	dwVictimVID;
    BYTE	bCRCMagicCubeProcPiece;
    BYTE	bCRCMagicCubeFilePiece;
};
05/22/2021 10:33 MrCrisp#10
Don't forget to pop at the end of your structs, and only use the pragma for structs/classes. Using it with enums will lead to problems :)