RO-PACKET-SENDER(6) Games Manual RO-PACKET-SENDER(6)

NAME

Ragnarok Online Packet Sender — A network experimentation tool for crafting and injecting raw hexadecimal packets into the Ragnarok Online stream.

METADATA

Platform: Ragnarok Online
Release: 2002-06-13
Status: Source available

SYNOPSIS

PacketSender.exe

DESCRIPTION

The Packet Sender was a tool developed to explore vulnerabilities in the RO client/server communication protocol. Heavily inspired by Techwarrior’s Diablo II packet sender, it provided a convenient interface for researchers to send raw hexadecimal data directly to the game server.

Unlike standard packet sniffers, this utility was designed specifically for active injection. By patching the game process memory, it could intercept the client’s outgoing “send” buffer or trigger its own socket transmissions, allowing users to test how the server handled malformed or unexpected data packets.

The archive includes only the source components:

  • Process.cpp — C++ logic for process attachment and packet buffer injection.
  • hackcodes.h — Offsets for the client’s socket transmission routines.

KEY FEATURES

  • Raw Hex Injection — Ability to manually craft packets in hexadecimal format to be sent directly to the server.
  • Packet Memory (Slots) — Supports storing up to 10 frequently used packets for rapid testing and repetition.
  • Profile Management — Allows saving and loading packet configurations using the .rop file extension.
  • Live Memory Patching — Patches the game at runtime to ensure the logic needed for the sender doesn’t interfere with standard gameplay until activated.

NOTES

The main purpose of this application was to find possible exploits and vulnerabilities in the client/server model of the game. It was a very convenient way to send packets compared to standard network traffic analyzers.

It was my last entry in the RO hacking scene. I don’t know if anyone found any exploits with it, but it was a fun project to work on.

ATTACHMENTS (Browsing /usr/games/hacks/)

Path: /usr/games/hacks/ragnarok_online/Packet Sender/readme.txt5576 bytes
Arsenic's Packet Sender For Ragnarok Online
                           
What's new in version 0.61
-------------------------
-  Fixed 2 errors that caused the program to crash under certain circumstances.

How to:
---------------
This program attaches itself to a running Ragnarok Online game client. You need to have the game
running before applying the patch.

Here are the steps to do it:
1) Run your Ragnarok Online client (ragnarok.exe or Ragexe.exe).
2) Press Alt+Tab (both keys) on your keyboard to minimize the game window.
3) Run this program.
4) Set up your stuffs and when you're done, click on "Apply".
5) Come back to the game and there you go.

Note that you will need to patch the hack for each different game instance, meaning that if you
exit the game and reopen it, you'll need to click on "Apply" (Or "Update", depending what was
the state of the button) again for it to work on this new process.

This program is compatible for every Windows 32 bits Operating System, exception of Windows NT.
I could make it works for WinNT, but don't count on it. Unless I receive a load of requests...

Basic Info:
---------------
This program is more than just a hack, it is an utility. This is a packet sender that attaches
itself to a running Ragnarok Online enlish Beta client.

It sends packets within the game client to the game server when pressing the proper hotkeys,
which are in the range of Alt+Keypad 0-9. Those packets are sent through the client software to
the game server at the right connected socket, all of this with the exact method that the client
sends packets usually. The server obviously doesn't see a difference and doesn't care, as long
as the packets are valid.

This is done via a patch in the game process memory, meaning the changes aren't permanent and
every coding in the client gets to its original state once the game terminates. The game must be
running to apply the patch, see the "How to" section for more information about this.

The main purpose of this application is to find possible exploits and vulnerabilities in the
client/server model of the game. Although there are similar tools that can do this kind of thing,
like some Network Traffic Analyzer or Packet Sniffer softwares, this program makes it all more
convenient to send packets, especially with how RO is designed.

The features:
- You can store up to 10 different packets, which each one can be send multiple times as well.
- It is possible to load/save packet files. You can save your current packet settings to a file,
and load the file at a later time to use it again. Packet files have the ".rop" extension, I
don't suggest you edit them manually, although it can be done quite easily.

Update - You have to click on it if you made any changes in the packets.
Unapply - You can unapply the patch at anytime to restore the changes in memory. You won't be 
able to send packets anymore when pressing the hotkeys.
Clear - This erases every packet settings (All of them). Use this if you want to start a new
packet file.

Newbie corner:
If you don't know by now, packets are represented in hexadecimal form, thus you need to type
packets in hex. Packets are actually a stream of hex bytes, and with each 2 hex digits forming a
byte, the lenght is an even number. Add a leading 0 to the byte if needed. You'll get an error
message otherwise when trying to apply.

Note that all space characters within the stream of bytes of a packet are filtered out, so it
really doesn't matter if you include some. It actually makes it easier to read. Yet, you can just
put each byte sided by side if you want.

Also, I made the maximum number of packets to send at 255. You'd probably get disconnected if
you'd send more than this anyway.

Disconnected?
If you're getting disconnected when sending a packet, it simply means that the packet isn't
valid, or contains invalid datas. Thus, the server rejects it and disconnects your client when
receiving it.

Not sent?
If packets aren't sent when you press the keys Alt+Keypad #, make sure that NumLock is on.

If you haven't noticed by now, this is not a final version. I have plenty of other features I
want to implement :)
I just wanted to release it as soon as possible so people could use it and have fun. I'll release
updated versions as time goes, so just stay tuned and check out my site or the Cheatlist forum
to get your hand on them.

I sure have many ideas, but if you have any suggestions feel free to let me know.

Credits:
Okay, if you're coming from the D2 hacking scene the first thing you'll remark is that the
interface of this program is really alike Techwarrior's D2 packet sender! In fact, it's almost
identical! I made it similiar and tried to include the same features, because his program was
very well done (Too bad he stopped updating it, eh?). His application is actually what gave me
the idea to make packet sender programs for other games. So I must say, as for the Windows
interface, credits go to Techwarrior, because I basically copied his own packet sender's one.

--------------------------------------

~ Arsenic

Don't waste time e-mailing me, if you have questions or want to contact me just drop by the
dedicated Ragnarok Online hacking forum on Cheatlist at:

http://forums.cheatlist.com/phpBB2/forumdisplay.php?s=&forumid=30

You need to register to see or post messages. Everyone is welcome to join.
        
Web page : http://onesided.cjb.net 
           www.onesided.da.ru  (Mirror)
Path: /usr/games/hacks/ragnarok_online/Packet Sender/Process.cpp11982 bytes
#include "stdafx.h"
#include "Process.h"
#include "Snapshot.h"

//Use this function with MFC
HWND FindWindow_( char *lpClassName, char *lpWindowName )
{
	return FindWindow( lpClassName, lpWindowName );
}

//Use this function with MFC
LRESULT SendMessage_( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam )
{
	return SendMessage( hWnd, Msg, wParam, lParam );
}

//Retrieves PID from a Class/Window name
DWORD GetProcessId( char *lpClass, char *lpWindow )
{
	HWND hWnd = FindWindow( lpClass, lpWindow );
	DWORD pid = 0;
		
	if ( hWnd )
		GetWindowThreadProcessId( hWnd, &pid );
		
	return pid;
}

//Returns an open handle to a process
//Process object has PROCESS_ALL_ACCESS	access
//Don't forget to close the handle
HANDLE GetProcessHandle( char *lpClass, char *lpWindow )
{
	HWND hWnd = FindWindow( lpClass, lpWindow );
	DWORD pid = 0;
	HANDLE pHandle = 0;
	
	if ( hWnd )
	{
		GetWindowThreadProcessId( hWnd, &pid );
		pHandle = OpenProcess( PROCESS_ALL_ACCESS, FALSE, pid );
	}
	
	return pHandle;
}


//Retrieves entry point address of a module (Exe only)
//This function searches the module image in the process memory, it only works if the
//process is running.
//To find the entry point of a module on disk, use the GetFileEntryPoint function.
DWORD GetModuleEntryPoint( char *ModuleName )
{
	DWORD EntryPoint = 0;
	DWORD ModBaseAddr;
	DWORD PE_Header_Offset;
	DWORD PE_Header_Addr;
	DWORD EntryPoint_Offset;
	
	DWORD pid = GetpidFromExe( ModuleName ); //From Snapshot.h
	ModBaseAddr = GetModBaseAddr( pid, ModuleName ); //From Snapshot.h
	
	if ( ModBaseAddr )
	{
		HANDLE hProcess = OpenProcess( PROCESS_VM_READ, FALSE, pid );		
		if (!hProcess) return 0;
		
		ReadProcessMemory( hProcess, (void*)(ModBaseAddr + DOSMZ_PE), &PE_Header_Offset, sizeof(DWORD), NULL );
		PE_Header_Addr = ModBaseAddr + PE_Header_Offset;
		ReadProcessMemory( hProcess, (void*)(PE_Header_Addr + PE_ENTRYPOINT), &EntryPoint_Offset, sizeof(DWORD), NULL );
		EntryPoint = ModBaseAddr + EntryPoint_Offset;
		
		CloseHandle( hProcess );
	}
	
	return EntryPoint;
}


//Retrieve the Window Procedure address of a window
DWORD GetWndProcAddr( char *lpClass, char *lpWindow )
{
	DWORD WndProcAddr = 0;
	HWND hWnd = FindWindow( lpClass, lpWindow );
	
	if (hWnd)
		WndProcAddr = GetClassLong( hWnd, GCL_WNDPROC );
		
	return WndProcAddr;
}

//Search byte-patterns in a module (exe or dll) and return offset
//Return 0 if not found
DWORD MemSearch( char *ModuleName, BYTE Data[], const int DataLen )
{
	ModuleInfo mi;	
	DWORD pid = GetpidFromExe( ModuleName );
	
	if (!pid) { return 0; } //Process is not running
	
	if ( GetModInfo( pid, ModuleName, mi ) )
	{
		const int BYTESCHUNK = 1000; //Chunk to be searched each time
		DWORD DataToRead = BYTESCHUNK;
		DWORD readOffset = mi.BaseAddr;
		BYTE fOffset;
		DWORD oldprot; //For VirtualProtectEx
		
		HANDLE hProcess = OpenProcess( PROCESS_VM_READ, FALSE, pid );
		BYTE ModData[ BYTESCHUNK ]; //Buffer for module datas			
		
		do
		{
			if ( mi.Size - readOffset < BYTESCHUNK )
				DataToRead = mi.Size - readOffset;
			
			if (!ReadProcessMemory(hProcess, (void*)readOffset, (void*)&ModData, DataToRead, NULL) )
			{
				VirtualProtectEx(hProcess, (void*)readOffset, DataToRead, PAGE_READWRITE, &oldprot);
				ReadProcessMemory(hProcess, (void*)readOffset, (void*)&ModData, DataToRead, NULL);
			}
			
			for ( register WORD x = 0; x < DataToRead; x++ )
			{
				fOffset = 0;
				while ( *(ModData + x + fOffset) == Data[fOffset] )
				{
					if ( fOffset < DataLen - 1 )
						fOffset += 1;
						
					else //Found!
					{
						CloseHandle( hProcess );
						return readOffset + x; //Address memory corresponding
					}						
				}
			}
			
			readOffset += BYTESCHUNK;				
						
		}while ( readOffset < mi.EndAddr );
		
		CloseHandle( hProcess );
	}
	
	return 0; //Couldn't retrieve module info or didn't find searched datas
}

//Read datas from a process
// Originally mousepads code
void ReadProcessBYTES(HANDLE hProcess, DWORD lpAddress, void* buf, int len)
{
	DWORD oldprot, dummy = 0;
	VirtualProtectEx(hProcess, (void*) lpAddress, len, PAGE_READWRITE, &oldprot);
	ReadProcessMemory(hProcess, (void*) lpAddress, buf, len, 0);
	VirtualProtectEx(hProcess, (void*) lpAddress, len, oldprot, &dummy);
}

//Write datas to a process
// Originally mousepads code
void WriteProcessBYTES(HANDLE hProcess, DWORD lpAddress, void* buf, int len)
{
	DWORD oldprot,dummy = 0;
	VirtualProtectEx(hProcess, (void*) lpAddress, len, PAGE_READWRITE, &oldprot);
	WriteProcessMemory(hProcess, (void*) lpAddress, buf, len, 0);
	VirtualProtectEx(hProcess, (void*) lpAddress, len, oldprot, &dummy);
}

//Return true if datas at address are exact
bool IsPatchOk( HANDLE hProcess, DWORD address, BYTE Data )
{	
	BYTE buffer;
	
	ReadProcessBYTES(hProcess, address, (void*) &buffer, 1);
	
	if ( buffer == Data )
		return true;
	
	return false;
}

//Compute the opcodes for a x86 call instruction
void MakeCall( BYTE opcodes[5], DWORD lpSource, DWORD lpDest )
{
	opcodes[0] = 0xe8;
	*(DWORD*) (opcodes+1) = lpDest - (lpSource + 5);
}

//Compute the opcodes for a x86 jmp instruction
void MakeJump( BYTE opcodes[5], DWORD lpSource, DWORD lpDest )
{
	opcodes[0] = 0xe9;
	*(DWORD*) (opcodes+1) = lpDest - (lpSource + 5);
}

// Originally mousepads/thohell code
// Copy original codes to the beggining of the Dest function
void InterceptCopy(HANDLE hProcess, int inst, DWORD lpSource, DWORD lpDest, int len)
{
	BYTE* buffer = new BYTE[len];
	ReadProcessBYTES(hProcess, lpSource, buffer, len);
	WriteProcessBYTES(hProcess, lpDest, buffer, len);

	if ( inst == 0xe8 )
		MakeCall( buffer, lpSource, lpDest );
	else
		MakeJump( buffer, lpSource, lpDest );
		
	memset(buffer + 5, 0x90, len - 5);		// nops

	WriteProcessBYTES(hProcess, lpSource, buffer, len);
	
	delete buffer;
}

//Modified function of mousepad/thohell, doesn't copy overwritten datas
void Intercept( HANDLE hProcess, int inst, DWORD lpSource, DWORD lpDest, int len )
{
	BYTE* buffer = new BYTE[len];
	
	if ( inst == 0xe8 )
		MakeCall( buffer, lpSource, lpDest );
	else
		MakeJump( buffer, lpSource, lpDest );
		
	memset(buffer + 5, 0x90, len - 5);	// NOPS

	WriteProcessBYTES(hProcess, lpSource, buffer, len);
	
	delete buffer;
}	

/***************************** Memory allocation ******************************/

#define DATA			0x200	// Offset between data+code
//Offsets for mem alloc structure:
#define PGETPROCESSHEAP		0x00
#define PHEAPALLOC		0x04
#define ALLOCSIZE		0x08
#define PALLOCREGION		0x0c
#define OLDWNDPROC		0x10
struct MEMALLOCDATA
{
	DWORD pGetProcessHeap; 	//GetProcessHeap API
	DWORD pHeapAlloc;	//HeapAlloc API
	DWORD AllocSize;	//Size in bytes to allocate
	DWORD pAllocRegion; 	//Pointer to the allocated memory region to retrieve
	BYTE OldWndProc[5];	//WndProc datas that we temporarily overwrite
};
	
void _declspec(naked) AllocAsm(void)
{
	__asm {
	pushad
	call getaddress
Getaddress:
	pop ebp
	sub ebp, 0x06			//EBP = Base address of code
	add ebp, DATA			//EBP = Base address of data
	mov eax, [esp+0x2c]		//uMsg
	cmp eax, WM_APP
	jz AllocMem
Quit:
	mov ebx, [esp+0x20]		//The return address
	sub ebx, 5
	mov [esp+0x20], ebx		//Little trick to return at the WndProc beginning ;)
	mov eax, [ebp+OLDWNDPROC]
	mov [ebx], eax			//Rewrite old WndProc datas
	add ebp, 4
	add ebx, 4
	mov al, [ebp+OLDWNDPROC]
	mov [ebx], al			//Rewrite old WndProc datas
	popad
	ret				//Return to the beginning of WndProc!	
	
AllocMem:
	mov eax, [ebp+ALLOCSIZE]
	push eax			//Size
	push HEAP_ZERO_MEMORY		//Flags
	mov eax, [ebp+PGETPROCESSHEAP]
	call eax
	push eax			//Default heap handle returned
	mov eax, [ebp+PHEAPALLOC]
	call eax			//Call HeapAlloc
	mov [ebp+PALLOCREGION], eax	//Put base address returned into struct data member
	jmp Quit
	}
}	
void _declspec(naked) AllocAsm_END(void){}

//Allocates memory in a target process
//Returns the base addr of the allocated memory space
//Returns NULL if failed
DWORD MemAllocProcess( char *lpWindow, char *ExeName, DWORD size )
{
	MEMALLOCDATA mad;	
	DWORD WndProcAddr, PatchAddr, DataAddr;
	HANDLE hProcess;
	BYTE oldWndProcData[5];
	HWND hWnd = FindWindow( lpWindow, lpWindow );
	
	WndProcAddr = GetClassLong( hWnd, GCL_WNDPROC ); //Get WndProc address
	if (!WndProcAddr) { return 0; } //Wrong window name, or isn't running
	DWORD pid = GetpidFromExe( ExeName );	
	if (!pid) { return 0; }		//Wrong exe name, or isn't running
	PatchAddr = GetModBaseAddr( pid, ExeName );
	PatchAddr += 0x400;
	DataAddr = PatchAddr + DATA;
	
	//Initiate the structure datas
	mad.AllocSize = size;
	mad.pAllocRegion = NULL;
	
	HMODULE hModule = GetModuleHandle("Kernel32.dll");
		if (!hModule) { MessageBox(NULL, "Unable to get handle of KERNEL32.DLL.", "Error", MB_ICONERROR); return -1;}
		
	mad.pGetProcessHeap = (DWORD)GetProcAddress(hModule, "GetProcessHeap");
	if (!mad.pGetProcessHeap ) { MessageBox(NULL, "Unable to get address of GetProcessHeap in KERNEL32.DLL.", "Error!", MB_ICONERROR); return -1;}
	
	mad.pHeapAlloc = (DWORD)GetProcAddress(hModule, "HeapAlloc");
	if (!mad.pHeapAlloc ) { MessageBox(NULL, "Unable to get address of HeapAlloc in KERNEL32.DLL.", "Error!", MB_ICONERROR); return -1;}
			
	hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, pid ); //Open process
	
	if ( hProcess )
	{
		//Copy old datas from WndProc
		ReadProcessBYTES( hProcess, WndProcAddr, oldWndProcData, 5 );
		memcpy( &mad.OldWndProc, &oldWndProcData, 5 );
		
		//Change access protections
		DWORD dum = 0;
		VirtualProtectEx(hProcess,(void*)DataAddr,sizeof(MEMALLOCDATA),PAGE_READWRITE,&dum);
		VirtualProtectEx(hProcess,(void*)WndProcAddr,5,PAGE_READWRITE,&dum);
		
		// Patch in our code
		WriteProcessBYTES( hProcess, PatchAddr, AllocAsm, FUNCTLEN(AllocAsm));	
		// Patch in our data
		WriteProcessBYTES( hProcess, DataAddr, &mad, sizeof(MEMALLOCDATA) );
				
		//Hook the WndProc and make it calls to our own function
		Intercept( hProcess, 0xe8, WndProcAddr, PatchAddr, 5 );
		
		// Send WM_APP to trigger the memory allocation
		SendMessage( hWnd, WM_APP,0,0);
		
		//Retrieve base address of the new allocated memory space
		ReadProcessBYTES( hProcess, DataAddr+PALLOCREGION, (void*)&mad.pAllocRegion, 4 );
		
		CloseHandle( hProcess );
		return mad.pAllocRegion;
	}
	
	return 0;
}
/***************************** Memory allocation END **************************/

//Converts an ASCII string into a stream of hex bytes
//Receives a byte pointer variable and sets it to the new pointer
//Returns the lenght of the hex array
//Returns 0 if the string is invalid - Lenght is not an even number
DWORD ConvertStringToHex( char *str, BYTE *&hexArray )
{				
	//Filter out spaces
	FilterSpace( str );
	
	int len = strlen( str );
			
	if ( len == 0 || len % 2 != 0 )
		return 0;
	
	hexArray = new BYTE[len/2];
	int i = 0; //Index
	BYTE tmp;	
		
	//Sort out the characters
	for (int x = 0; x < len; x += 2)
	{					
		if ( !isxdigit( str[x] ) || !isxdigit( str[x+1] ) ) //If char isn't a hexadecimal digit
		{
			delete [] hexArray;
			return 0;
		}
		
		str[x] = toupper( str[x] );
		str[x+1] = toupper( str[x+1] );
		
		if ( isdigit( str[x] ) )
			tmp = (str[x] - 0x30) << 4;
			
		else
			tmp = (str[x] - 0x37) << 4;
		
		if ( isdigit( str[x+1] ) )
			tmp += str[x+1] - 0x30;
			
		else
			tmp += str[x+1] - 0x37;
			
		hexArray[ i++ ] = tmp;
	}			
	
	return (DWORD)len/2;
}

void FilterSpace( char* str )
{	
	int len = strlen( str );
	char *tmp = new char[ len+1 ];
	int i = 0;
	
	for (int x = 0; x < len; x++)
		if ( !isspace( str[x] ) ) //If not a space character
		{
			tmp[i] = str[x];
			i++;
		}
		
	tmp[i] = '\0';	
	strcpy( str, tmp );	
	delete [] tmp;			
}
Path: /usr/games/hacks/ragnarok_online/Packet Sender/hackcodes.h5650 bytes
#ifndef _HACKCODES
#define _HACKCODES

char *gameWindow = "Ragnarok";
char *gameExe	 = "Ragexe.exe";

//A call from the game keyboard routine to our own stub
class GAME_KEYBOARD_TO_PACKETSENDER
{
 public:
 	DWORD Address;	//Memory address to patch
 	BYTE *Search;	//Datas to search to find address
	int Size;	//Size of datas
	BYTE *Old;	//Old datas for unload
	int OldSize;	//Old datas size
 
	GAME_KEYBOARD_TO_PACKETSENDER()
	{
		BYTE tmp[] = {0x83,0xc0,0xf7,0x57,0x3d,0xd3,0x00,0x00,0x00};
		BYTE oldbuf[] = {0x8b,0x44,0x24,0x04,0x56};
		
		Address = 0;
		Size = sizeof(tmp);
		OldSize = sizeof(oldbuf);		
		Search = new BYTE[Size];
		memcpy( Search, tmp, Size );		
		Old = new BYTE[OldSize];
		memcpy( Old, oldbuf, OldSize );
		
		sOffset = -5;
	}
	
	~GAME_KEYBOARD_TO_PACKETSENDER()
	{
		delete [] Search;
		delete [] Old;
	}
	
	void SetAddress()
	{
		if (Address)
			Address += sOffset; //Compute address to patch
	}
 private:
 	signed int sOffset; //Offset for found Address
}KeyCall;

//The in-game packet sending function
class IN_GAME_PACKET_SENDING_FCT
{
 public:
 	DWORD Address;	//Memory address for function
 	BYTE *Search;	//Datas to search to find address
	int Size;	//Size of datas
 
	IN_GAME_PACKET_SENDING_FCT()
	{
		BYTE tmp[] = {0xff,0x0f,0x84,0x1f,0x01,0x00,0x00,0x8d,0xb7};
		
		Address = 0;
		Size = sizeof(tmp);	
		Search = new BYTE[Size];
		memcpy( Search, tmp, Size );
		
		sOffset = -9;
	}
	
	~IN_GAME_PACKET_SENDING_FCT()
	{
		delete [] Search;
	}
	
	void SetAddress()
	{
		if (Address)
			Address += sOffset; //Compute address to patch
	}
 private:
 	signed int sOffset; //Offset for found Address
}PacketFct;

//Special parameter to pass to the packet sending function
class GAME_PACKET_SENDING_SPECIAL_POINTER
{
 public:
 	DWORD Address;	//Memory address to patch
 	BYTE *Search;	//Datas to search to find address
	int Size;	//Size of datas
 
	GAME_PACKET_SENDING_SPECIAL_POINTER()
	{
		BYTE tmp[] = "WinSock 2.0";
		
		Address = 0;
		Size = sizeof(tmp);	
		Search = new BYTE[Size];
		memcpy( Search, tmp, Size );
		
		sOffset = -28;
	}
	
	~GAME_PACKET_SENDING_SPECIAL_POINTER()
	{
		delete [] Search;
	}
	
	void SetAddress()
	{
		if (Address)
			Address += sOffset; //Compute address to patch
	}
 private:
 	signed int sOffset; //Offset for found Address
}WinSockPointer;


// -- Packet Sender ASM (The stub from the keyboard hook) --
#define SENDERDATA	0x100	// Offset between data+code
#define PACKETSIZE	0xff	//Max lenght of a packet
//Offsets for mem alloc structure:
#define PGETASYNCKEYSTATE	0x00
#define RETURNADDR		0x04
#define PACKETSENDINGFCT	0x08
#define SPECIALPOINTER		0x0c
#define PACKET1			0x10
#define PACKET2			(PACKET1+PACKETSIZE+2)
#define PACKET3			(PACKET2+PACKETSIZE+2)
#define PACKET4			(PACKET3+PACKETSIZE+2)
#define PACKET5			(PACKET4+PACKETSIZE+2)
#define PACKET6			(PACKET5+PACKETSIZE+2)
#define PACKET7			(PACKET6+PACKETSIZE+2)
#define PACKET8			(PACKET7+PACKETSIZE+2)
#define PACKET9			(PACKET8+PACKETSIZE+2)
#define PACKET10		(PACKET9+PACKETSIZE+2)
struct _SENDERDATA_
{
	DWORD pGetAsyncKeyState;
	DWORD ReturnAddr;
	DWORD PacketSendingFct;
	DWORD SpecialPointer;
	BYTE packet1[PACKETSIZE+2];
	BYTE packet2[PACKETSIZE+2];
	BYTE packet3[PACKETSIZE+2];
	BYTE packet4[PACKETSIZE+2];
	BYTE packet5[PACKETSIZE+2];
	BYTE packet6[PACKETSIZE+2];
	BYTE packet7[PACKETSIZE+2];
	BYTE packet8[PACKETSIZE+2];
	BYTE packet9[PACKETSIZE+2];
	BYTE packet10[PACKETSIZE+2];
}psd;

void _declspec(naked) PacketSenderAsm(void)
{
	__asm {
	__asm nop __asm nop __asm nop __asm nop __asm nop //Old datas overwritten
	pushad
	call getaddress
Getaddress:
	pop ebp
	sub ebp, 0x0b			//EBP = Base address of code
	add ebp, SENDERDATA		//EBP = Base address of data
	cmp eax, VK_NUMPAD0
	jb Quit
	cmp eax, VK_NUMPAD9
	jbe CheckAlt
Quit:
	mov eax, [ebp+RETURNADDR]
	mov [esp-4], eax
	popad
	sub esp, 0x24
	ret 0x20

CheckAlt:
	mov ebx, eax				//EBX = key pressed
	mov edi, [ebp+PGETASYNCKEYSTATE]
	push 0x12
	call edi
	xor ecx, ecx
	mov cl, ah
	test cl, cl
	jz Quit
	cmp ebx, VK_NUMPAD1
	jnz Packet_2
	lea esi, [ebp+PACKET1+2]	//Offset of packet1
Packet_2:
	cmp ebx, VK_NUMPAD2
	jnz Packet_3
	lea esi, [ebp+PACKET2+2]	//Offset of packet2
Packet_3:
	cmp ebx, VK_NUMPAD3
	jnz Packet_4
	lea esi, [ebp+PACKET3+2]	//Offset of packet3
Packet_4:
	cmp ebx, VK_NUMPAD4
	jnz Packet_5
	lea esi, [ebp+PACKET4+2]	//Offset of packet4
Packet_5:
	cmp ebx, VK_NUMPAD5
	jnz Packet_6
	lea esi, [ebp+PACKET5+2]	//Offset of packet5
Packet_6:
	cmp ebx, VK_NUMPAD6
	jnz Packet_7
	lea esi, [ebp+PACKET6+2]	//Offset of packet6
Packet_7:
	cmp ebx, VK_NUMPAD7
	jnz Packet_8
	lea esi, [ebp+PACKET7+2]	//Offset of packet7
Packet_8:
	cmp ebx, VK_NUMPAD8
	jnz Packet_9
	lea esi, [ebp+PACKET8+2]	//Offset of packet8
Packet_9:
	cmp ebx, VK_NUMPAD9
	jnz Packet_10
	lea esi, [ebp+PACKET9+2]	//Offset of packet9
Packet_10:
	cmp ebx, VK_NUMPAD0
	jnz SendPacket
	lea esi, [ebp+PACKET10+2]	//Offset of packet10
SendPacket:
	xor ecx, ecx
	xor edx, edx
	xor edi, edi
	mov dl, [esi-2]		//Size of packet
	cmp dl, 00
	jz Quit
	mov edi, edx
	mov cl, [esi-1]		//Number of packets to send
SendLoop:
	push ecx			//Back up number

	push esi			//Packet address
	push edi			//Packet size
	mov ecx, [ebp+SPECIALPOINTER]	//Winsock pointer in ecx
	mov eax, [ebp+PACKETSENDINGFCT]
	call eax			//Call in-game packet sending function
	pop ecx
	loop SendLoop
	jmp Quit
	}
}	
void _declspec(naked) PacketSenderAsm_END(void){}
	
#endif

TECHNOLOGIES

  • C++
  • Network Security
  • Packet Injection
int03h.com circa 2002 RO-PACKET-SENDER(6)