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
.ropfile 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/)
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)#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;
}#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){}
#endifTECHNOLOGIES
- C++
- Network Security
- Packet Injection