[Release] Advanced hooking

07/08/2011 02:50 Belth#46
Since the encryption seems to have changed enough to stump me I finally decided to look into this. Quite blown away by how easy it is to use but two things not explained in any sample are bothering me:

1. How to block a packet from being received by/sent from the client.

2. How to send packets to the client.
07/08/2011 03:08 IAmHawtness#47
Quote:
Originally Posted by Belth View Post
Since the encryption seems to have changed enough to stump me I finally decided to look into this. Quite blown away by how easy it is to use but two things not explained in any sample are bothering me:

1. How to block packets.

2. How to send packets to the clients.
There's many different ways of blocking say a client->server packet. For example, if you place your hook at the start of the SendPacket function, you could simply just change the instruction pointer (Context.EIP) to any random "retn8" instruction - because that is how the function returns, with a retn8 instruction. You'll see this if you look at the function in ollydbg (or whatever disassembler you prefer). That way, you'll skip the entire function that actually encrypts and sends the packet to the server.

I'm not sure what you mean by "send packets to the client", but I'm assuming you mean faking a packet from the server sent to the client? If so, you just either call the "ProcessMessage" function, or you edit the loop where Conquer checks for received packets and replace them with your own packets. That's kinda tricky unless you know what you're doing though.
07/08/2011 03:48 Belth#48
Quote:
Originally Posted by IAmHawtness View Post
There's many different ways of blocking say a client->server packet. For example, if you place your hook at the start of the SendPacket function, you could simply just change the instruction pointer (Context.EIP) to any random "retn8" instruction - because that is how the function returns, with a retn8 instruction. You'll see this if you look at the function in ollydbg (or whatever disassembler you prefer). That way, you'll skip the entire function that actually encrypts and sends the packet to the server.

I'm not sure what you mean by "send packets to the client", but I'm assuming you mean faking a packet from the server sent to the client? If so, you just either call the "ProcessMessage" function, or you edit the loop where Conquer checks for received packets and replace them with your own packets. That's kinda tricky unless you know what you're doing though.
I generally haven't a clue :p. I've asked questions [Only registered and activated users can see links. Click Here To Register...] about it but never got anywhere really (probably my own fault).

So, I don't know how to "change the instruction pointer (Context.EIP) to any random "retn8" instruction" though I understand what that means.

I think I may understand how to call the "ProcessMessage" function after going through your SendPacket function in the sample.

Edit:

Just realised the SendPacket function no longer works so I'm even more lost than I thought. So basically I'm looking for how to intercept and subsequently block/relay a packet sent from the server or client.
07/08/2011 13:29 phize#49
Quote:
Originally Posted by Belth View Post
I generally haven't a clue :p. I've asked questions [Only registered and activated users can see links. Click Here To Register...] about it but never got anywhere really (probably my own fault).

So, I don't know how to "change the instruction pointer (Context.EIP) to any random "retn8" instruction" though I understand what that means.

I think I may understand how to call the "ProcessMessage" function after going through your SendPacket function in the sample.

Edit:

Just realised the SendPacket function no longer works so I'm even more lost than I thought. So basically I'm looking for how to intercept and subsequently block/relay a packet sent from the server or client.
You don't change EIP, you overwrite the instructions about to get executed with a RETN 8. Just remember to preserve the original code so you can restore it after it's been executed. It's way easier to do something like this if you are in-process (dll) but doing it externally is awesome.

Truth is you won't get far with this without any reverse engineering skills. I recommend lena's tutorials on tuts4you.com

Edit: Didn't read the previous posts, you can change EIP instead if you happen to find a retn 8 instruction :p

Code:
if (AimBot->OnChat(TokenizeStr(text, " ")) == 0)
{
	CONTEXT* c = (CONTEXT*)GetContext();
	c->Eip = Pattern->GetAddress("LeaveRetn18Loc");
}
That is so much cleaner! :)
07/08/2011 14:47 IAmHawtness#50
Quote:
Originally Posted by Synsia View Post
Code:
if (AimBot->OnChat(TokenizeStr(text, " ")) == 0)
{
	CONTEXT* c = (CONTEXT*)GetContext();
	c->Eip = Pattern->GetAddress("LeaveRetn18Loc");
}
That is so much cleaner! :)
Isn't that code executed "in-process", from your injected DLL?
If so, why not just make your own "retn8" function inside the DLL, and re-direct the EIP to that function? Instead of using the Pattern->GetAddress

Code:
void Handler(char[] text)
{
  if (AimBot->OnChat(TokenizeStr(text, " ")) == 0)
  {
    CONTEXT* c = (CONTEXT*)GetContext();
    c->Eip = &Retn8Function
  }
}

int Retn8Function
{
  __asm
  {
    retn 8
  }
}
My C++ isn't that great (almost non-existant), but I think you get the point :p
07/08/2011 14:58 phize#51
Nah, that's using the win debug api from an extern process.

I was overwriting instruction code to force a RETN but that seems overkill, when you can just change EIP. I don't know why I never thought of that to be honest lol.
07/08/2011 15:02 IAmHawtness#52
Quote:
Originally Posted by Synsia View Post
Nah, that's using the win debug api from an extern process.

I was overwriting instruction code to force a RETN but that seems overkill, when you can just change EIP. I don't know why I never thought of that to be honest lol.
Haha, I see :D. Hell, there's like a million ways to "skip" functions, since most well-coded functions check for all kind of things to prevent errors, I could even imagine that the SendPacket function might check for a 0 length packet, if so it would be possible to skip the packet just by modifying the PacketLength parameter. :p
07/08/2011 15:09 phize#53
Quote:
Originally Posted by IAmHawtness View Post
Haha, I see :D. Hell, there's like a million ways to "skip" functions, since most well-coded functions check for all kind of things to prevent errors, I could even imagine that the SendPacket function might check for a 0 length packet, if so it would be possible to skip the packet just by modifying the PacketLength parameter. :p
True that :p
07/08/2011 18:06 Belth#54
Quote:
Originally Posted by Synsia View Post
Truth is you won't get far with this without any reverse engineering skills.
All I needed to know, thanks.
07/09/2011 10:01 Belth#55
May I get some help as to what is wrong with this method?

Code:
public void SendPacket(byte[] packet)
{[INDENT]int packetType = BitConverter.ToUInt16(packet, 2);
int packetAddr = (int)this.Dbg.AllocateMemory((uint)packet.Length);
this.Dbg.WriteByteArray(packet, (int)packetAddr);

byte[] buffer = new byte[]
{ [INDENT]0xBA, 0x00, 0x00, 0x00, 0x00,	// mov edx, 0; reserved for packet type
0x68, 0x00, 0x00, 0x00, 0x00,	// push 0 ; reserved for packet size
0x68, 0x00, 0x00, 0x00, 0x00,	// push 0 ; reserved for packet address
0xB9, 0x00, 0x00, 0x80, 0x00,	// move ecx, 0; reserved for NetWorkClass
0x60, 0x12, 0x80,				// mov ecx, [esi+14]
0xB8, 0x00, 0x00, 0x00, 0x00,	// mov eax, SendPacketFn; reserved for SendPacket() Address
0xFF, 0xD0,					// call eax; call SendPacket()
0xC3,						// RET[/INDENT]};

using (BinaryWriter writer = new BinaryWriter(new MemoryStream(buffer)))
{[INDENT]writer.BaseStream.Position++;
writer.Write(packetType);
writer.BaseStream.Position++;
writer.Write(packet.Length);
writer.BaseStream.Position++;
writer.Write(packetAddr);
writer.BaseStream.Position++;
writer.Write(NetworkClass);
writer.BaseStream.Position += 4;
writer.Write(SendPacketAddress);[/INDENT]}
this.Dbg.ExecuteCode(buffer);
this.Dbg.FreeMemory(packetAddr);[/INDENT]}
07/09/2011 10:25 phize#56
The way you're overwriting the buffer does not look right at all. Only incrementing position by 1?
07/09/2011 20:47 Belth#57
Quote:
Originally Posted by Synsia View Post
The way you're overwriting the buffer does not look right at all. Only incrementing position by 1?
The original buffer is almost certainly wrong anyways. Hawtness said that SendPacket() takes two parameters, size and address so I figure this part has to be right:

Code:
using (MemoryStream ms = new MemoryStream())
using (BinaryWriter writer = new BinaryWriter(ms))
{[INDENT]// push packet size
writer.Write((byte)0x68);
writer.Write(packet.Length);

// push packet address
writer.Write((byte)0x68);
writer.Write(packetAddress);

// store SendPacket() address in EAX
writer.Write((byte)0xB8);
writer.Write(SendPacketAddress);

// call function stored in EAX
writer.Write(new byte[] {0xFF, 0xD0});

// return
writer.Write((byte)0xC3);[/INDENT]				
}
Simple and I understand that. What I don't understand is why in the sample he does:

Code:
mov edx, packetType - [COLOR="Red"]why the hell would I need to do this?[/COLOR]
push packetSize
push packetAddress
mov esi, networkClass - [COLOR="Red"]why the hell would I need to do this?[/COLOR]
mov ecx, [esi+14] - [COLOR="Red"]and subsequently, this?[/COLOR]
mov eax, sendpacketfunction
call eax
ret
Then Ian posts his own function which seemed a lot easier to read and is almost what I expected:

Code:
unsafe public void SendPacket(byte[] packet)
{[INDENT]int packetAdr = AllocMem(packet.Length);
Write(packetAdr, packet);
byte[] buffer = new byte[]
{[INDENT]0x68, 0x00, 0x00, 0x00, 0x00,    // PUSH 0 ; Size
0x68, 0x00, 0x00, 0x00, 0x00,    // PUSH 0 ; Packet
0xB9, 0x60, 0x12, 0x80, 0x00,    // MOV ECX, SendPacketEcx - [COLOR="Red"]why?[/COLOR]
0xB8, 0x00, 0x00, 0x00, 0x00,    // MOV EAX, SendPacketFn
0xFF, 0xD0,                        // CALL EAX
0xC3,                            // RET[/INDENT]};
fixed (byte* ptr = buffer)
{[INDENT]
*((int*)(ptr + 1)) = packet.Length;
*((int*)(ptr + 6)) = packetAdr;
*((int*)(ptr + 11)) = SendPacketEcx;
*((int*)(ptr + 16)) = SendPacketFn;
[/INDENT]}
Execute(buffer);
FreeMem(packetAdr);[/INDENT]}
AND either way executing both of these in memory crashes the client so I'm assuming some part of both is outdated though I can't imagine what.
07/09/2011 21:39 phize#58
Quote:
Originally Posted by Belth View Post
The original buffer is almost certainly wrong anyways. Hawtness said that SendPacket() takes two parameters, size and address so I figure this part has to be right:

Code:
using (MemoryStream ms = new MemoryStream())
using (BinaryWriter writer = new BinaryWriter(ms))
{[INDENT]// push packet size
writer.Write((byte)0x68);
writer.Write(packet.Length);

// push packet address
writer.Write((byte)0x68);
writer.Write(packetAddress);

// store SendPacket() address in EAX
writer.Write((byte)0xB8);
writer.Write(SendPacketAddress);

// call function stored in EAX
writer.Write(new byte[] {0xFF, 0xD0});

// return
writer.Write((byte)0xC3);[/INDENT]				
}
Simple and I understand that. What I don't understand is why in the sample he does:

Code:
mov edx, packetType - [COLOR="Red"]why the hell would I need to do this?[/COLOR]
push packetSize
push packetAddress
mov esi, networkClass - [COLOR="Red"]why the hell would I need to do this?[/COLOR]
mov ecx, [esi+14] - [COLOR="Red"]and subsequently, this?[/COLOR]
mov eax, sendpacketfunction
call eax
ret
Then Ian posts his own function which seemed a lot easier to read and is almost what I expected:

Code:
unsafe public void SendPacket(byte[] packet)
{[INDENT]int packetAdr = AllocMem(packet.Length);
Write(packetAdr, packet);
byte[] buffer = new byte[]
{[INDENT]0x68, 0x00, 0x00, 0x00, 0x00,    // PUSH 0 ; Size
0x68, 0x00, 0x00, 0x00, 0x00,    // PUSH 0 ; Packet
0xB9, 0x60, 0x12, 0x80, 0x00,    // MOV ECX, SendPacketEcx - [COLOR="Red"]why?[/COLOR]
0xB8, 0x00, 0x00, 0x00, 0x00,    // MOV EAX, SendPacketFn
0xFF, 0xD0,                        // CALL EAX
0xC3,                            // RET[/INDENT]};
fixed (byte* ptr = buffer)
{[INDENT]
*((int*)(ptr + 1)) = packet.Length;
*((int*)(ptr + 6)) = packetAdr;
*((int*)(ptr + 11)) = SendPacketEcx;
*((int*)(ptr + 16)) = SendPacketFn;
[/INDENT]}
Execute(buffer);
FreeMem(packetAdr);[/INDENT]}
AND either way executing both of these in memory crashes the client so I'm assuming some part of both is outdated though I can't imagine what.
The SendPacket function takes two params, that is the pushes you wrote in opcodes. But you can't simply pass the address of your buffer from another process space, you have to allocate space (VirtualAllocEx) for it in the target process, then write the buffer there (WriteProcessMemory) and finally pushing that address you just allocated. When you're done with the buffer you injected you need to free it (VirtualFreeEx), or you'll have a memory leak

ECX is a "this"-pointer, which points to a class instance (some socket class in this case). It's needed in order to call class member functions that are non-static.

Edit: I just noticed that you do allocate memory for it, hah.
Well, your crashes could be due to addresses being outdated.
07/09/2011 22:27 Belth#59
Quote:
Originally Posted by Synsia View Post
The SendPacket function takes two params, that is the pushes you wrote in opcodes. But you can't simply pass the address of your buffer from another process space, you have to allocate space (VirtualAllocEx) for it in the target process, then write the buffer there (WriteProcessMemory) and finally pushing that address you just allocated. When you're done with the buffer you injected you need to free it (VirtualFreeEx), or you'll have a memory leak

ECX is a "this"-pointer, which points to a class instance (some socket class in this case). It's needed in order to call class member functions that are non-static.

Edit: I just noticed that you do allocate memory for it, hah.
Well, your crashes could be due to addresses being outdated.
Ah, you cleared up the ECX thing for me. So Ian's function makes sense, though it still crashes the client.

const int SendPacketAddress = 0x6E01B7;
const int RecvPacketAddress = 0x6E2809;

Aren't those the right addresses for the latest client? (5509)

Also, why does Hawtness store the packet type in EDX?
07/09/2011 22:50 phize#60
SendFunc: 0x6dfee2

I have no idea why he's using edx, but it's not needed to call the function.