Osem.forumms.net
Selamat datang ke
Osem Forum Komuniti!

Sila klik Login untuk masuk atau
klik Register untuk pendaftaran baru.
Latest topics
» New Release (Daily Update)
Mon Jul 25, 2016 10:46 am by bayu_inzaghi

» Trumbo (2015)
Fri Jul 15, 2016 7:12 am by bayu_inzaghi

» Solace (2015)
Thu Jul 14, 2016 10:36 am by bayu_inzaghi

» Courage (2015)
Tue Jul 12, 2016 7:50 pm by bayu_inzaghi

» Ronaldo (2015)
Mon Jul 11, 2016 7:22 am by bayu_inzaghi

» The Witch (2015)
Sat Jul 09, 2016 10:20 pm by bayu_inzaghi

» Jeruzalem (2015)
Sat Jul 09, 2016 12:37 am by bayu_inzaghi

» Intruders (2015)
Fri Jul 08, 2016 12:40 am by bayu_inzaghi

» Moonwalkers (2015)
Thu Jul 07, 2016 11:03 am by bayu_inzaghi

October 2018
MonTueWedThuFriSatSun
1234567
891011121314
15161718192021
22232425262728
293031    

Calendar Calendar


The Power of MHS: Generic Packet Editor

Go down

The Power of MHS: Generic Packet Editor

Post by mezzo on Wed Jun 06, 2012 10:11 am

Exceeder posted asking for adding a "packet scanner & editor" to MHS and his request inspired me to show off the power of L. Spiro Script once again. Why 'add' a packet editor to MHS when you can write your own without much effort?

WS2_32.dll:send(), WS2_32.dll:recv(), and WSOCK32.dll:recv() are the three functions I'm going to concentrate on in this tutorial. In the research I've done--and I truly hope that L. Spiro or someone else can give more information on this--nearly all Winsock-based programs use WS2_32.dll:send() to send information, whereas the newer games use WS2_32.dll:recv() to receive information and the older ones use WSOCK32.dll:recv(). That, of course, is just backed by the games I currently have installed on my computer and is by no means conclusive. However, of the games I checked, none of them used BOTH of the receive functions, so breakpointing both functions didn't hurt any.

WS2_32.dll:send()

The send() function is very straight-forward: the 2nd parameter passed to the function is a pointer to an array of bytes that make up the packet of information being sent and the 3rd parameter passed to the function is the length, in bytes, of the packet. All we have to do is breakpoint near the start of the function, parse the packet from the 2nd parameter, change anything we want to change, and pass control back to the executing thread. This is the easiest of the breakpoints to set and easiest to understand.

The only ASM we have to pay attention to in this function is the part that aligns the stack. Attach MHS to your favorite game (if you haven't already) and open up the Disassembler window. On the Helper portion of the Disassembler window, click the Exports tab, then scroll down until you see WS2_32.dll or WSOCK32.dll (either one should do just fine, though if you see WS2_32.dll, choose that one). Click the + button, then scroll down until you see send. Right-click on send and choose Goto Function. Your diassembler window should change and display something like:

Code:
    71AB428A | 8BFF    | MOV    EDI, EDI |
    71AB428C | 55      | PUSH    EBP      |
    71AB428D | 8BEC    | MOV    EBP, ESP | ;moves stack pointer into EBP
    71AB428F | 83EC 10 | SUB    ESP, 10  |

We're going to be breakpointing on the fourth line, SUB ESP, 10. Whether we use a Hardware or Software breakpoint, the stack will be aligned by the time the breakpoint is hit and an aligned stack means we'll have no problem getting the parameters off of it. At 71AB428F, the stack looks like this:
EBP+0x00: Old EBP
EBP+0x04: Return Address of Calling Function
EBP+0x08: Parameter 1 -- socket
EBP+0x0C: Parameter 2 -- packet buffer
EBP+0x10: Parameter 3 -- length
EBP+0x14: Parameter 4 -- flags
etc...

So, to grab the 2nd and 3rd parameters, we have to read EBP+0x08 and EBP+0x0C. First, lets set up the function that will handle this breakpoint, then we'll compile and set the breakpoint.


//handler for our WSOCK32/WS2_32:send breakpoint
void On_BP_1(LPVOID lpvAddress, LPPROC_INFO_MHS lpProcInfo)
{
//EBP+0x0C == 2nd parameter, or a pointer to the packet
extern DWORD ptr = {"", lpProcInfo->pcContext->Ebp + 0x0C};
//EBP+0x10 == 3rd parameter, or length
extern int len = {"", lpProcInfo->pcContext->Ebp + 0x10};

//buffer into which we'll read the packet, 2kb should be more than enough, even
//for the longest packet we encounter (hopefully)
BYTE packet[2048] = {0};
//string which we use to display the packet
//needs to be three times as big as the packet itself
char packetstr[6144] = {0};

//read len bytes from packetptr into packet
ReadProcessMemory(GetCurProcessHandle(), (void *)ptr, &packet, len, NULL);

//populate the packet string so we can output it to console
for (int i = 0; i < len; i++)
SPrintF(&packetstr[(i * 3)], "%02X ", packet[i]);

//output the string to console
PrintF("SEND | % 3i | %s", len, packetstr);
}

It's rather well commented, but just so we're clear: if you want to compare the packet to something or change the packet around, you'd do so directly after the ReadProcessMemory call. Make any changes to byte array packet as you want, then WriteProcessMemory(GetCurProcessHandle(), (void *)ptr, packet, len, NULL);.

Save the script as whatever you want. Choose File -> Add to Scripts. Either hit [F5] or click the Compile button in the bottom-right.

Now, to set the breakpoint, go back to the Disassembler window and right-click on the line that says SUB ESP, 10. Choose Breakpoints -> Add Breakpoint Here. Put in a name that reminds you that this is the WS2_32:send() breakpoint (the name doesn't actually matter at all). Make sure both On Execute and Hardware are selected/checked. Set the Callback Function to Script Function by choosing it out of the dropdown box; make sure to set the Parm for Callback Function to 1 (note: the function we wrote is called On_BP_1, which is why the Parm for Callback Function needs to be 1 as well).

Now the script is compiled and the breakpoint is set; you are more than welcome to test this out and see how you're doing. Go do something in the game, i.e. logging in or moving or something, that sends information to the server. You should see the packet show up in your Code Editor window console.

WSOCK32.dll:recv()

This function is pretty easy, too, as it calls WSARecv() to read bytes off of the socket stream. We'll just breakpoint directly after that call.


Code:
    71AD2E9E  E8 17000000      CALL <JMP.&WS2_32.WSARecv>
    71AD2EA3  83F8 FF          CMP EAX,-1

We breakpoint on line 71AD2EA3. Here's the breakpoint handler:

//handler for our WSOCK32:recv breakpoint
void On_BP_2(LPVOID lpvAddress, LPPROC_INFO_MHS lpProcInfo)
{
//make sure WSARecv() didn't fail
if (lpProcInfo->pcContext->Eax == -1)
return;

//pointer to the packet
extern DWORD ptr = {"", lpProcInfo->pcContext->Ebp - 0x04};
//number of bytes read by WSARecv()
extern int len = {"", lpProcInfo->pcContext->Ebp + 0x10};

//buffer into which we'll read the packet, 2kb should be more than enough, even
//for the longest packet
BYTE packet[2048] = {0};
//string which we use to display the packet
//needs to be three times as big as the packet itself
char packetstr[6144] = {0};

//read the received packet from memory
ReadProcessMemory(GetCurProcessHandle(), (void *)ptr, &packet, len, NULL);

//populate the packet string so we can output it to console
for (int i = 0; i < len; i++)
SPrintF(&packetstr[(i * 3)], "%02X ", packet[i]);

//output the string to console
PrintF("RECV | % 3i | %s", len, packetstr);
}

Set the breakpoint exactly like before, on the CMP EAX, -1 instruction. Be sure to name it something so that you know it's the WSOCK32:recv breakpoint; also make sure the Parm is set to 2.

WS2_32.dll:recv()

This function is slightly more complex. The buffer is not populated with the bytes of the packet of information until right before the function returns, so we can't just breakpoint at the start of the function. If you wanted to do this all yourself, you'd catch the pointer that is passed as the 2nd parameter (buffer into which the bytes will be received), load that up in the Hex Editor, then step through the function until those bytes have been changed. We'll breakpoint on one of the instructions after the bytes have been changed, seeing as I already stepped through the function and found where that is.

Code:
    71AB61CD  E8 54C9FFFF      CALL WS2_32.71AB2B26
    71AB61D2  3BFB            CMP EDI,EBX
    71AB61D4  5F              POP EDI
    71AB61D5  75 2E            JNZ SHORT WS2_32.71AB6205
    71AB61D7  F645 15 80      TEST BYTE PTR SS:[EBP+15],80
    71AB61DB  75 3F            JNZ SHORT WS2_32.71AB621C
    71AB61DD  8B45 08          MOV EAX,DWORD PTR SS:[EBP+8]
    71AB61E0  5E              POP ESI
    71AB61E1  5B              POP EBX
    71AB61E2  C9              LEAVE
    71AB61E3  C2 1000          RETN 10

At 71AB61CD, the bytes are actually read from the socket stream into memory. At 71AB61DD, the number of bytes that were read from the socket stream is moved into EAX, so this is where we breakpoint.

Now, the breakpoint handler:

//handler for our WS2_32:recv() breakpoint
void On_BP_3(LPVOID lpvAddress, LPPROC_INFO_MHS lpProcInfo)
{
//set external variable 'len' as the number of bytes read
extern DWORD len = {"", lpProcInfo->pcContext->Ebp + 0x08};
//gather the pointer to the packet of information
extern DWORD ptr = {"", lpProcInfo->pcContext->Ebp + 0x0C};

//if -1 bytes were returned, or len equals zero, don't go any further
if ((int)lpProcInfo->pcContext->Eax == -1 || len == 0)
return;

//byte array into which we'll read the packet
BYTE packet[2048] = {0};
//string we use to display the packet
char packetstr[6144] = {0};

//read the packet from memory
ReadProcessMemory(GetCurProcessHandle(), (void *)ptr, &packet, len, NULL);

//populate the packet string so we can output it to console
for (int i = 0; i < len; i++)
SPrintF(&packetstr[(i * 3)], "%02X ", packet[i]);

//output the string to console
PrintF("RECV | % 3i | %s", len, packetstr);
}

Set the breakpoint just like the other two times on the MOV EAX, [EBP+8] line. Make sure, again, to name it something so you know it's the WS2_32:recv() breakpoint; again, make sure the Parm is 3.



So, to recap: we have three breakpoints and three breakpoint handling script functions. Highlight all of the breakpoints in the breakpoint tab by shift+clicking them all, then right-click one and save them as wsock_breakpoints.bps or something. Remove them all, compile the script, load the breakpoints back, and test to see if it works. You should get a very nice readout of all the packets sent to and from the current process.


I'm sure I've left a few things out as this is the second time I'm writing this--my computer crashed the last time I got to this point and I lost it all. If you see any discrepancies or have any suggestions or questions, please post.



EDIT: For those of you who like automation and don't want to have to go through these steps, here's an addition to the script that (should) automatically set(s) the breakpoints:

[code] void On_OpenProcess(HANDLE hProcess, DWORD dwProcessId)
{
//wsock32_send = GetRemoteFuncAddress("WSOCK32.dll", "send");
wsock32_recv = GetRemoteFuncAddress("WSOCK32.dll", "recv");
ws2_32_send = GetRemoteFuncAddress("WS2_32.dll", "send");
ws2_32_recv = GetRemoteFuncAddress("WS2_32.dll", "recv");

//MessageBox(MBS_OK, "SLDKFJLS", "WSOCK32.dll:recv(): 0x%08X\nWS2_32.dll:send(): 0x%08X\nWS2_32.dll:recv(): 0x%08X", wsock32_recv, ws2_32_send, ws2_32_recv);

if (MessageBox(MBS_YES|MBS_NO, "Enable Packet Editing/Sniffing?", "Would you like to enable the packet editing/sniffing breakpoints for %s?", GetCurProcessName()) == MBS_NO)
return;

AttachDebugger();

SCRIPT_ADD_BP ws2_send_bp = {0};
ws2_send_bp.aAddress = ws2_32_send + 0x05;
ws2_send_bp.iType = SPBT_EXECUTE;
ws2_send_bp.bHardware = true;
ws2_send_bp.iCallback = SYS_FUNCS_SCRIPT_FUNC;
ws2_send_bp.dwNewParms[1] = 1;
ws2_send_bp.bSet = true;
AddBreakpoint(&ws2_send_bp, NULL);

SCRIPT_ADD_BP wsock32_recv_bp = {0};
wsock32_recv_bp.aAddress = wsock32_recv + 0x33;
wsock32_recv_bp.iType = SPBT_EXECUTE;
wsock32_recv_bp.bHardware = true;
wsock32_recv_bp.iCallback = SYS_FUNCS_SCRIPT_FUNC;
wsock32_recv_bp.dwNewParms[1] = 2;
wsock32_recv_bp.bSet = true;
AddBreakpoint(&wsock32_recv_bp, NULL);

SCRIPT_ADD_BP ws2_recv_bp = {0};
ws2_recv_bp.aAddress = ws2_32_send + 0x83;
ws2_recv_bp.iType = SPBT_EXECUTE;
ws2_recv_bp.bHardware = true;
ws2_recv_bp.iCallback = SYS_FUNCS_SCRIPT_FUNC;
ws2_recv_bp.dwNewParms[1] = 3;
ws2_recv_bp.bSet = true;
AddBreakpoint(&ws2_recv_bp, NULL);
}

- WhiteHat -


Sir Hacks Alot
avatar
mezzo
Limited Osem Member
Limited Osem Member

Posts : 66
Treasure : 102
Reputation : 10
Join date : 03/06/2012
Location : Kyiv, Ukraine

View user profile

Back to top Go down

Back to top


 
Permissions in this forum:
You cannot reply to topics in this forum