• Welcome to Valhalla Legends Archive.
 

packet DWORDS [solved]

Started by z-stars, July 21, 2004, 01:29 PM

Previous topic - Next topic

z-stars

I'm making a packet builder for a bot in C++ and I wanna make a function that takes a DWORD (unsigned long) and puts it into a 4 bytes array. For example, if the DWORD's value was 10, the bytes array would have to be {0x00, 0x00, 0x00, 0x0A}. The problem is that I dunno how to do that. Thx in advance for ur help.
(PS: I know that the dwords of a packet are in LittleEndian order but the order can be shifted later I think?)

shadypalm88

Take this advice with a grain of salt; I'm pretty new to C++ and am also writing a C++ packet buffer atm.  However I did create a working buffer in Java and I'm basically porting it to C++.  Basically you need to extract the relevant byte from the long and cast it onto a char.  So if you have a char array named buffer, a variable called buflen keeping track of the length, and a variable called DWord containing the unsigned long, this code should work:

buffer[buflen++] = (char) (DWord & 0x000000FF);
buffer[buflen++] = (char) ((DWord & 0x0000FF00) >> 8);
buffer[buflen++] = (char) ((DWord & 0x00FF0000) >> 16);
buffer[buflen++] = (char) ((DWord & 0xFF000000) >> 24);

As I used another buffer (don't remember where I got it) as a reference to create my Java buffer, my assumptions might not be correct.  The bitmask being AND'd with the DWORD preserves the byte you are currently interested in while setting the others to 0.  The shifts move the byte you want to the point where the cast to a char will catch it.  It's not a very good explanation; someone please correct me where I'm wrong

Kp

Quote from: z-stars on July 21, 2004, 01:29 PMI'm making a packet builder for a bot in C++ and I wanna make a function that takes a DWORD (unsigned long) and puts it into a 4 bytes array. For example, if the DWORD's value was 10, the bytes array would have to be {0x00, 0x00, 0x00, 0x0A}. The problem is that I dunno how to do that. Thx in advance for ur help.
(PS: I know that the dwords of a packet are in LittleEndian order but the order can be shifted later I think?)

Easy.  Mask out 8 bits at a time, storing each masked value into the appropriate array cell.  Sample C code follows, which will produce the result you mentioned.  Note that the result you mentioned is backwards from what most of us expect when we say to insert a dword into the buffer. :)


buf[ 3 ] = mylong & 0xff; mylong >>= 8;
buf[ 2 ] = mylong & 0xff; mylong >>= 8;
buf[ 1 ] = mylong & 0xff; buf[ 0 ] = mylong >> 8;
[19:20:23] (BotNet) <[vL]Kp> Any idiot can make a bot with CSB, and many do!

z-stars

Thank you ppl it works  :)

iago

#4
That's the easy way to do it, but not really the right way.  Look up pointers :)
This'll make an interesting test for broken AV:
QuoteX5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*


Kp

Quote from: iago on July 21, 2004, 02:24 PMThat's the easy way to do it, but not really the right way.  Look up pointers :)

What pointer-based solution do you propose for meeting the specified criteria?
[19:20:23] (BotNet) <[vL]Kp> Any idiot can make a bot with CSB, and many do!

K

#6
suppose you have a byte array:


// an array of 64 unsigned characters.
BYTE bBuffer[64];


and an integer that tells you where the next data should be put:

int iNextPutIndex = 16;
// the first unused index of the byte array bBuffer
// i.e, bBuffer[16] is one past the end of our current data


now, since we know that a DWORD is simply four bytes, and is represented like so in memory, and that a BYTE array is simply a block of 64 bytes in memory, let's have some pointer fun.


// this is the value we want to insert.
DWORD dwToWrite = 0x00ABCDEF;
// get the address in memory of the dword we want to write.
DWORD* lpdwAddrOfdwToWrite = &dwToWrite;


so now, think of our pointer to a dword as simply an array of four bytes.  that's all an object in memory is, right? groups of bytes?

So we could do this:

BYTE* bFourBytes = reinterpret_cast<BYTE*>(lpdwAddrOfdwToWrite);

// put the four bytes into our array
for(int i = 0; i < 4; ++i)
   bBuffer[iNextPutIndex++] = bFourBytes[i];


or, we could just copy it over into the byte array we already have, like this:


BYTE* bFourBytes = reinterpret_cast<BYTE*>(lpdwAddOrdwToWrite);
memcpy(&bBuffer[iNextPutIndex], bFourBytes, 4);

iNextPutIndex += 4;


My code may be a little verbose, but that's the basic idea.  Good luck!
Edit: Added memcpy length arg.   :P

Kp

I expected to catch somebody screwing up and not reading the project specifications.  I didn't expect it to be K. :)  The original poster asked to have the lowermost byte of the long end up in the rightmost byte of result, which would be true on a big endian system.  However, most (all?) bot development seems to be done on little endian systems, so a direct memory copy from one pointer to another will end up with the wrong order, relative to what the poster specified.

Also, minor correction to K's code.  memcpy takes three arguments, not two.  The third argument is the amount to copy.  See the manpage for full details.
[19:20:23] (BotNet) <[vL]Kp> Any idiot can make a bot with CSB, and many do!

K

Quote from: Kp on July 21, 2004, 04:27 PM
I expected to catch somebody screwing up and not reading the project specifications.  I didn't expect it to be K. :)  The original poster asked to have the lowermost byte of the long end up in the rightmost byte of result, which would be true on a big endian system.  However, most (all?) bot development seems to be done on little endian systems, so a direct memory copy from one pointer to another will end up with the wrong order, relative to what the poster specified.

Also, minor correction to K's code.  memcpy takes three arguments, not two.  The third argument is the amount to copy.  See the manpage for full details.


Well fine, use htonl first.   ;)  You're right, I completely missed the endianness.

tA-Kane

#9
So to recap, ya'll have gone over apparently three ways of putting a DWORD into a BYTE array, two very similar with endian conversion, one directly.

Very long, with endian conversion:
buffer[buflen++] = (char) (DWord & 0x000000FF);
buffer[buflen++] = (char) ((DWord & 0x0000FF00) >> 8);
buffer[buflen++] = (char) ((DWord & 0x00FF0000) >> 16);
buffer[buflen++] = (char) ((DWord & 0xFF000000) >> 24);


Not as long, with endian conversion:
buf[ 3 ] = mylong & 0xff; mylong >>= 8;
buf[ 2 ] = mylong & 0xff; mylong >>= 8;
buf[ 1 ] = mylong & 0xff;
buf[ 0 ] = mylong >> 8;


Long and confusing, without endian conversion:
// an array of 64 unsigned characters.
BYTE bBuffer[64];
int iNextPutIndex = 16;
// the first unused index of the byte array bBuffer
// i.e, bBuffer[16] is one past the end of our current data
// this is the value we want to insert.
DWORD dwToWrite = 0x00ABCDEF;
// get the address in memory of the dword we want to write.
DWORD* lpdwAddrOfdwToWrite = &dwToWrite;

BYTE* bFourBytes = reinterpret_cast<BYTE*>(lpdwAddrOfdwToWrite);

// put the four bytes into our array
for(int i = 0; i < 4; ++i)
   bBuffer[iNextPutIndex++] = bFourBytes[i];

BYTE* bFourBytes = reinterpret_cast<BYTE*>(lpdwAddOrdwToWrite);
memcpy(&bBuffer[iNextPutIndex], bFourBytes, 4);

iNextPutIndex += 4;



Now, for my solution, which is fairly short, quite simple, and even has endian conversion:
char Dst[4];
long *Buffer, Value;

Value = 0x12345678;
Buffer = (long *)Dst;
/* buffer now points to the char array Dst */
*Buffer = ChangeEndian32(Value);
/* Dst now contains the characters 0x78, 0x56, 0x34, and 0x12 in that order */


Note that you'll need ROR32, ROL32, and ChangeEndian32 (rotate right, rotate left, and change endianness for 32 bits, respectively), which are defined as:
#define ROR32(value,count) ((value >> count) | (value << (32-count)))
#define ROL32(value,count) ((value << count) | (value >> (32-count)))
#define ChangeEndian32(value) (ROL32(value & 0xFF00FF00, 8) | ROR32(value & 0x00FF00FF, 8))
These #defines should go into a header file, since they're used fairly often (especially so if you're needing endian swapping capability). Since they go into a header file, I don't count them toward the size of that code...  ;)


Edit:
Quote from: K on July 21, 2004, 04:31 PMWell fine, use htonl first.   ;)  You're right, I completely missed the endianness.
The problem with using htonl is that it's not going to do anything if the network byte order and the host byte order are the same, is it?
Macintosh programmer and enthusiast.
Battle.net Bot Programming: http://www.bash.org/?240059
I can write programs. Can you right them?

http://www.clan-mac.com
http://www.eve-online.com

dxoigmn

Quote from: tA-Kane on July 22, 2004, 12:16 PM
Edit:
Quote from: K on July 21, 2004, 04:31 PMWell fine, use htonl first.   ;)  You're right, I completely missed the endianness.
The problem with using htonl is that it's not going to do anything if the network byte order and the host byte order are the same, is it?

How is using htonl a problem?

Adron

#11
htonl is a great function to use. It means the code works on all systems.

Now for some code:


union { char buf[4]; unsigned int dword; };
dword = htonl(10);


or simply


char buf[4];
*reinterpret_cast<unsigned long*>(buf) = htonl(10);

tA-Kane

What about when the network byte order is the same as the host byte order? Would htonl still swap the endianness? By the definition of "host to network (long)", it would not.

I'll give you an example.

Mac OS X's host byte order is the same as network byte order; Big Endian. That is, the value 0x12345678 is exactly that when stored in memory. It's not stored as 0x78 0x56 0x34 0x12.

Now if you wanted to send that value to Battle.net, you'd need to send the bytes 0x78 0x56 0x34 0x12, instead of the "natural" bytes of 0x12 0x34 0x56 0x78. Using htonl() in this case would not be beneficial, would it, since htonl() would (should) do nothing?

So, if Mac OS X were to use htonl() with 0x12345678, and then send that to Battle.net, Battle.net would receive 0x12 0x34 0x56 0x78. Battle.net would then read that as 0x78563412, which is a different value than origionally sent.

Sure, the code works on all systems, but that doesn't mean that it has the desired results.

Am I wrong?
Macintosh programmer and enthusiast.
Battle.net Bot Programming: http://www.bash.org/?240059
I can write programs. Can you right them?

http://www.clan-mac.com
http://www.eve-online.com

dxoigmn

Quote from: tA-Kane on July 22, 2004, 11:31 PM
What about when the network byte order is the same as the host byte order? Would htonl still swap the endianness? By the definition of "host to network (long)", it would not.

I'll give you an example.

Mac OS X's host byte order is the same as network byte order; Big Endian. That is, the value 0x12345678 is exactly that when stored in memory. It's not stored as 0x78 0x56 0x34 0x12.

Now if you wanted to send that value to Battle.net, you'd need to send the bytes 0x78 0x56 0x34 0x12, instead of the "natural" bytes of 0x12 0x34 0x56 0x78. Using htonl() in this case would not be beneficial, would it, since htonl() would (should) do nothing?

So, if Mac OS X were to use htonl() with 0x12345678, and then send that to Battle.net, Battle.net would receive 0x12 0x34 0x56 0x78. Battle.net would then read that as 0x78563412, which is a different value than origionally sent.

Sure, the code works on all systems, but that doesn't mean that it has the desired results.

Am I wrong?

The original specification calls for the byte order to be big-endian so there should be no problem.

Adron

Quote from: tA-Kane on July 22, 2004, 11:31 PM
Am I wrong?

You're wrong in this problem. If you don't use htonl, but use some code to always swap the bytes, you'll be swapping the bytes wrong on systems where the bytes were already right from the start (i.e. Mac OS X).

You should look more closely at the original specification. He asked for how to put the bytes in network byte order, not how to put them in the byte order battle.net expects.