Register for your free account! | Forgot your password?

You last visited: Today at 12:56

  • Please register to post and access all features, it's quick, easy and FREE!

Advertisement



Detouring SendPacket

Discussion on Detouring SendPacket within the PW Hacks, Bots, Cheats, Exploits forum part of the Perfect World category.

Reply
 
Old   #1
 
elite*gold: 0
Join Date: Mar 2013
Posts: 4
Received Thanks: 1
Detouring SendPacket

Hello there.
I'm posting about my problem since I haven't found any thread about this topic
I am trying to make an 'outgoing packet listener' for this game, by detour-ing its SendPacket function. Obviously it only listens for packets being sent.
I want to avoid using MS Detours, so I'm using a detour function I found on the internet.
Needless to say I am injecting a dll into the client in order to do that.
The problem is the game crashes, most likely when jumping from my custom SendPacket function to the real SendPacket function (according to OllyDbg).

Here's the code (C++) for the dll I'm injecting into the client:
Code:
#define WIN32_LEAN_AND_MEAN
#include <iostream>
#include <cstdio>
#include <windows.h>
#include <process.h>
#include <io.h>
#include <fcntl.h>

typedef int (__stdcall *pSendPacket) (void *Src, size_t Size);

unsigned int __stdcall mainThread(void* pArguments);
bool OpenConsole();
void SetConsoleTitle(wchar_t *title);
void *SetDetour(BYTE *source, const BYTE *destination, const unsigned int length);

pSendPacket o_SendPacket = NULL;
int _stdcall h_SendPacket(void *Src, size_t Size);

extern "C" __declspec(dllexport) BOOL APIENTRY DllMain(HANDLE hModule, DWORD lpReason, LPVOID lpReserved)
{
	switch (lpReason)
	{
		case DLL_PROCESS_ATTACH:
			// attach to process
			HANDLE hThread;
			unsigned int threadId;
			hThread = (HANDLE)_beginthreadex(NULL, 0x1000, &mainThread, (void *)hModule, 0, &threadId);
			break;
		case DLL_PROCESS_DETACH:
			// detach from process
			break;
		case DLL_THREAD_ATTACH:
			// attach to thread
			break;
		case DLL_THREAD_DETACH:
			// detach from thread
			break;
	}
	return TRUE; // succesful
}

unsigned int __stdcall mainThread(void* pArguments)
{
	OpenConsole();
	SetConsoleTitle(L"Packet Listener");
	DWORD addr = 0x63AA80; // sendpacket's address (old version of the game, I play on a private server, 1.4.4 I believe)
	o_SendPacket = (pSendPacket)SetDetour((BYTE *)addr, (BYTE *)h_SendPacket, 7); // detour SendPacket, it should now jump to h_SendPacket
	wprintf(L"SendPacket's address:   %x\nh_SendPacket's address: %x\no_SendPacket's address: %x\n", (BYTE *)addr, h_SendPacket, o_SendPacket); // check the functions' addresses, to make it easier to debug
	return S_OK; // exit current thread
}

bool OpenConsole()
{
	FILE *out;
	FILE *in;
	FILE *err;
	if (AllocConsole() == FALSE)
		return false;
	out = _fdopen(_open_osfhandle(PtrToUlong(GetStdHandle(STD_OUTPUT_HANDLE)), _O_TEXT), "w");
	in = _fdopen(_open_osfhandle(PtrToUlong(GetStdHandle(STD_INPUT_HANDLE)), _O_TEXT), "r");
	err = _fdopen(_open_osfhandle(PtrToUlong(GetStdHandle(STD_ERROR_HANDLE)), _O_TEXT), "w");
	*stdout = *out;
	*stdin = *in;
	*stderr = *err;
	setvbuf(stdout, NULL, _IONBF, 0);
	setvbuf(stdin, NULL, _IONBF, 0);
	setvbuf(stderr, NULL, _IONBF, 0);
	return true;
}

void SetConsoleTitle(wchar_t *title)
{
	SetConsoleTitleW(title);
}

void *SetDetour(BYTE *source, const BYTE *destination, const unsigned int length) // this wasn't written by myself
{
		BYTE *jmp = (BYTE *)malloc(length + 5);
		DWORD dwBack;
		VirtualProtect(source, length, PAGE_EXECUTE_READWRITE, &dwBack);
		memcpy(jmp, source, length);
		jmp += length;
		jmp[0] = 0xE9;
		*(DWORD *)(jmp + 1) = (DWORD)(source + length - jmp) - 5;
		source[0] = 0xE9;
		*(DWORD*)(source + 1) = (DWORD)(destination - source) - 5;
		for(int i = 5; i < length; i++)
		{
			source[i] = 0x90;
		}
		VirtualProtect(source, length, dwBack, &dwBack);
		return jmp - length + 1;
}

int __stdcall h_SendPacket(void *Src, size_t Size)
{
	wprintf(L"SendPacket triggered! opcode: %x (%d bytes long)\n", ((BYTE *)Src)[0], (int)Size); // check the packet's opcode, to make sure it works
	return o_SendPacket(Src, Size);
}
It compiles fine. I inject it into the client with a simple dll injector, and here's what happen:
1) A console gets attached to the client.
2) I move/sit/attack/whatever.. in game to trigger SendPacket.
3) SendPacket gets called, it jumps to my custom SendPacket (h_SendPacket in my code) which prints text on the console.
4) Crash.

I assume that it crashes when jumping back to the real SendPacket, maybe it screws up the registers?
This method used to work for me on other games, and I'm still a noob at Olly/ASM, so I'm kinda clueless for now
Salim* is offline  
Old 03/23/2013, 15:45   #2
 
Sᴡoosh's Avatar
 
elite*gold: 20
Join Date: May 2009
Posts: 1,290
Received Thanks: 326
Why do you not want to use ms detours? They work well.

I'd not rely on some detour method you found, but instead create it manually.

Start of sendpacket :

006B4220 /$ 6A FF PUSH -1
006B4222 |. 68 68A3A600 PUSH elementc.00A6A368
006B4227 |. 64:A1 00000000 MOV EAX, DWORD PTR FS:[0]

You need 5 byte for a jump, and the first two instructions are 7 bytes long. So, pushad, NOP 7 byte, place your jmp (so you have 2 byte nop behind it), and in your function, before you return, you push what the sendpacket function needs. Then popad.

Something along these lines. I see your detour function is basically doing this already, but if it crashes, i'd try doing it manually and see if the crash is fixed then. Then you at least know it's the detour doing funny stuff, and not something else.

Cheers
Sᴡoosh is offline  
Thanks
1 User
Old 03/23/2013, 21:17   #3
 
elite*gold: 0
Join Date: Mar 2013
Posts: 4
Received Thanks: 1
Okay, got it working now
There were 2 mistakes in my code.
The first one is I did not push the parameters needed for SendPacket.
Second one is my code was giving a wrong offset to one of the JMPs.

It is now working properly, I'll post a sample later on, if anyone wants to give a look at it.
Next step will be doing the same thing for incomming packets (hooking the function that decrypts those will be enough hopefully ).

__EDIT__

Here's the final source code:
Code:
#define WIN32_LEAN_AND_MEAN
#include <iostream>
#include <cstdio>
#include <windows.h>
#include <process.h>
#include <io.h>
#include <fcntl.h>

typedef int (__stdcall *pSendPacket) (void *Src, size_t Size);

unsigned int __stdcall mainThread(void* pArguments);
bool OpenConsole();
void SetConsoleTitle(wchar_t *title);
void *SetDetour(BYTE *source, const BYTE *destination, const unsigned int length);

pSendPacket o_SendPacket = NULL;
int _stdcall h_SendPacket(void *Src, size_t Size);

DWORD SendPacketAddress(0x63AA80);
DWORD BaseAddress(0xA521C0);

extern "C" __declspec(dllexport) BOOL APIENTRY DllMain(HANDLE hModule, DWORD lpReason, LPVOID lpReserved)
{
	switch (lpReason)
	{
		case DLL_PROCESS_ATTACH:
			// attach to process
			HANDLE hThread;
			unsigned int threadId;
			hThread = (HANDLE)_beginthreadex(NULL, 0x1000, &mainThread, (void *)hModule, 0, &threadId);
			break;
		case DLL_PROCESS_DETACH:
			// detach from process
			break;
		case DLL_THREAD_ATTACH:
			// attach to thread
			break;
		case DLL_THREAD_DETACH:
			// detach from thread
			break;
	}
	return TRUE; // succesful
}

unsigned int __stdcall mainThread(void* pArguments)
{
	OpenConsole();
	SetConsoleTitle(L"Packet Listener");
	o_SendPacket = (pSendPacket)SetDetour((BYTE *)SendPacketAddress, (BYTE *)h_SendPacket, 7); // detour SendPacket, it should now jump to h_SendPacket

	return S_OK; // exit current thread
}

void *SetDetour(BYTE *source, const BYTE *destination, unsigned int length)
{
	unsigned int const jmpLength(5);
	unsigned int const nopOpcode(0x90);
	unsigned int const jmpOpcode(0xE9);

	if (length < jmpLength) length = jmpLength; // Make sure the patch's length is long enough to hold a 32bit JMP.
	unsigned int tunnelLength = length + jmpLength;
	BYTE *tunnel = new BYTE[tunnelLength]; // Create a body for the "tunnel" function.
	FillMemory(tunnel, 12, 0);
	DWORD oldProtection(NULL); // Old page protection.
	VirtualProtect(source, length, PAGE_EXECUTE_READWRITE, &oldProtection);
	memcpy(tunnel, source, length);
	for (unsigned int i(jmpLength); i < length; i++)
		source[i] = nopOpcode;
	source[0] = jmpOpcode;
	tunnel[tunnelLength - jmpLength] = jmpOpcode;
	*(DWORD*)(source + 1) = (DWORD)(destination - source) - jmpLength; // JMP Offset 1
	*(DWORD*)(tunnel + 1 + tunnelLength - jmpLength) = (DWORD)((source + length) - (tunnel + tunnelLength - jmpLength) - jmpLength); // JMP Offset 2
	VirtualProtect(source, length, oldProtection, &oldProtection);
	return tunnel;
}

bool OpenConsole()
{
	FILE *out;
	FILE *in;
	FILE *err;
	if (AllocConsole() == FALSE)
		return false;
	out = _fdopen(_open_osfhandle(PtrToUlong(GetStdHandle(STD_OUTPUT_HANDLE)), _O_TEXT), "w");
	in = _fdopen(_open_osfhandle(PtrToUlong(GetStdHandle(STD_INPUT_HANDLE)), _O_TEXT), "r");
	err = _fdopen(_open_osfhandle(PtrToUlong(GetStdHandle(STD_ERROR_HANDLE)), _O_TEXT), "w");
	*stdout = *out;
	*stdin = *in;
	*stderr = *err;
	setvbuf(stdout, NULL, _IONBF, 0);
	setvbuf(stdin, NULL, _IONBF, 0);
	setvbuf(stderr, NULL, _IONBF, 0);
	return true;
}

void SetConsoleTitle(wchar_t *title)
{
	SetConsoleTitleW(title);
}

int __stdcall h_SendPacket(void *packet, size_t len)
{
	wprintf(L"Packet type: %02X\n", ((BYTE *)packet)[0]); // Display the packet's opcode (first byte).
	DWORD ecx_val = *(DWORD *)(*(DWORD *)BaseAddress + 0x20);
	__asm
	{
		push ecx
		push len
		push packet
		mov ecx,ecx_val
		call o_SendPacket
		pop ecx
	}
}
It displays the first byte of the packets being sent in the console (too lazy to make it output the whole packet ).
Salim* is offline  
Thanks
1 User
Old 03/24/2013, 11:52   #4
 
AlainProvist's Avatar
 
elite*gold: 0
Join Date: Aug 2012
Posts: 381
Received Thanks: 562
Thanks for sharing your code .

What method do you use for injecting your dll inside the client ?
AlainProvist is offline  
Old 03/24/2013, 15:00   #5
 
elite*gold: 0
Join Date: Mar 2013
Posts: 4
Received Thanks: 1
Any injector should work, you can find plenty of them on the internet.
I have not try to code one myself yet, however I think you can do it by calling LoadLibraryA into the client via WriteProcessMemory and CreateRemoteThread.
If I get my head around it and get some code working I post it here.
Salim* is offline  
Old 03/24/2013, 16:15   #6
 
AlainProvist's Avatar
 
elite*gold: 0
Join Date: Aug 2012
Posts: 381
Received Thanks: 562
I wrote my own injector :

Code:
#include <iostream>
#include <windows.h>
#include <WindowsX.h>
#include <tchar.h>
#include <malloc.h>
#include <direct.h>
#include <TlHelp32.h>

BOOL InjectLibrary(DWORD processID, const char *fnDll)
{
	HANDLE hProcess = OpenProcess(
		PROCESS_QUERY_INFORMATION | PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION  | PROCESS_VM_WRITE,
		FALSE, processID);
	if (!hProcess)
	{
		return false;
	}

	BOOL success = FALSE;
	HANDLE hThread = NULL;
	char *fnRemote = NULL;
	FARPROC procLoadLibraryA = NULL;

	size_t lenFilename = strlen(fnDll) + 1;

	/* Allocate space in the remote process */
	fnRemote = (char *) VirtualAllocEx(hProcess, NULL, lenFilename, MEM_COMMIT, PAGE_READWRITE);

	if(fnRemote)
	{
		/* Write the filename to the remote process. */
		if(WriteProcessMemory(hProcess, fnRemote, fnDll, lenFilename, NULL))
		{
			/* Get the address of the LoadLibraryA function */
			procLoadLibraryA = GetProcAddress(GetModuleHandle("Kernel32"), "LoadLibraryA");
			hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE) procLoadLibraryA, fnRemote, 0, NULL);
			if(hThread)
			{
				WaitForSingleObject(hThread, INFINITE);
				success = TRUE;
			}
		}
		VirtualFreeEx(hProcess, fnRemote, 0, MEM_RELEASE);
	}

	CloseHandle(hProcess);

	return success;
}

BOOL EjectLibrary(DWORD processID, const char *fnDll)
{
	HANDLE hProcess = OpenProcess(
		PROCESS_QUERY_INFORMATION | PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION  | PROCESS_VM_WRITE,
		FALSE, processID);
	if (!hProcess)
	{
		return false;
	}

	BOOL success = FALSE;
	HANDLE hSnapshot = NULL;
	HANDLE hThread = NULL;
	FARPROC procFreeLibrary = NULL;

	hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, processID);

	if(hSnapshot)
	{
		MODULEENTRY32 me = { sizeof(me) };
		BOOL isFound = FALSE;
		BOOL isMoreMods = Module32First(hSnapshot, &me);
		for(; isMoreMods && !isFound; isMoreMods = Module32Next(hSnapshot, &me))
			isFound = (_strcmpi(me.szModule, fnDll) == 0 || _strcmpi(me.szExePath, fnDll) == 0);

		if(isFound)
		{
			/* Get the address of the LoadLibraryA function */
			procFreeLibrary = GetProcAddress(GetModuleHandle("Kernel32"), "FreeLibrary");
			hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE) procFreeLibrary, me.modBaseAddr, 0, NULL);
			if(hThread)
			{
				WaitForSingleObject(hThread, INFINITE);
				success = TRUE;
			}
		}

		CloseHandle(hSnapshot);	
	}

	CloseHandle(hProcess);

	return success;
}

int _tmain(int argc, _TCHAR* argv[])
{
	char srcDll[512]; //dll in the same directory as the injection.exe, its code is specified below.
	_getcwd(srcDll, 512);
	strcat(srcDll, "\\Detouring.dll");

	DWORD processID; 
	std::cout << "Enter any PID : ";
	std::cin >> processID;
	if (InjectLibrary(processID, srcDll))
	{
		std::cout << "Injection successful" << std::endl;
	}
	system("PAUSE");

	EjectLibrary(processID, srcDll);

	return 0;
}
For some strange reason the EjectLibrary() make the client crash when FreeLibrary is called. I don't even get any DLL_PROCESS_DETACH from my dll before the crash. Any idea of why it crashes the client ?
(I would like to make it detachable for debug purpose when I want to modify the dll without restarting the client.)
AlainProvist is offline  
Old 03/24/2013, 16:17   #7
 
elite*gold: 0
Join Date: Mar 2013
Posts: 2
Received Thanks: 1
Most common injection techniques I can think of are proxy DLLs (often used for dx hooks) and, as you said, calling LoadLibrary in the target process to load your DLL.
LoadLibrary is probably the easiest way of doing it, but you will need to know the client's ID in order to use all the APIs needed. You can retrieve it at runtime by using a snapshot of the running processes (nice tutorial here: ).
Alternatively, you can run the client from your injector by using CreateProcess, which will give you the process' ID right away

Here's an old code I've got that uses the 2nd method (CreateProcess).
The error checking is pretty bad, but as long as it works.. xD
Code:
#include <iostream>
#include <Windows.h>
using namespace std;

typedef HINSTANCE (*fpLoadLibrary)(char*);
bool inject(DWORD pId);

wchar_t processPath[] = L"elementclient.exe";
wchar_t dllPath[] = L"myDll.exe"; //Replace myDll.exe by the name of your DLL.

int main()
{
	STARTUPINFOW startupInfo = {0};
	PROCESS_INFORMATION processInfo = {0}; //This struct will hold the process' ID.
	if (!CreateProcessW(NULL, processPath, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &startupInfo, &processInfo)) //Try to create the process (elementclient) and 'pause' it.
	{ //Creation failed.
		wcout << L"Error: Process creation failed.\n";
	}
	else //Process succesfully created.
	{
		if (inject(processInfo.dwProcessId)) //Try to inject the DLL.
			ResumeThread(processInfo.hThread); //Succesful, resume the process.
		else
		{ //Failed. Too bad.
			wcout << L"Error: Dll injection failed.\n";
			TerminateThread(processInfo.hThread, 0); //Close the process.
		}
	}
}

bool inject(DWORD pId)
{
	bool memWritten;
	HINSTANCE hDll = LoadLibrary(L"KERNEL32");
	fpLoadLibrary LoadLibraryAddr = (fpLoadLibrary)GetProcAddress(hDll, "LoadLibraryW"); //Get LoadLibraryW's address.
	HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, false, pId); //Get the process' handle.
	if (!hProc) //Ret if OpenProcess failed.
		return false;
	LPVOID paramAddr = VirtualAllocEx(hProc, 0, wcslen(dllPath) + 1, MEM_COMMIT, PAGE_READWRITE); //Allocate some bytes to copy our dll's name.
	memWritten = WriteProcessMemory(hProc, paramAddr, dllPath, wcslen(dllPath) + 1, NULL); //Write the dll's name into the bytes.
	if (memWritten)
		CreateRemoteThread(hProc, 0, 0, (LPTHREAD_START_ROUTINE)LoadLibraryAddr, paramAddr, 0, 0); //Run LoadLibraryW in elementclient and feed it our dll.
	CloseHandle(hProc); //We're done.
	return memWritten; //memWritten = TRUE if WriteProcessMemory was succesful.
}
For runtime injection, just replace the CreateProcess part with a process snapshot, and check the processes one by one until you find elementclient.exe.

1rst Edit: Wow, ninja'd, you beat me at it Alain xD

2nd Edit:
Since Salim's DLL detours sendpacket, if you unload the dll, the client will try to call an unexisting function, resulting in a crash. You should restore the original sendpacket before unloading .
Also make sure to change the following lines in his code if you're running it on the latest client - those addresses are fairly outdated:
DWORD SendPacketAddress(0x63AA80);
DWORD BaseAddress(0xA521C0);
Arkendo is offline  
Thanks
1 User
Old 03/24/2013, 17:15   #8
 
AlainProvist's Avatar
 
elite*gold: 0
Join Date: Aug 2012
Posts: 381
Received Thanks: 562
Yes for sure but i was supposing my dll would have call the dllmain with DLL_PROCESS_DETACH reason param to let me undetour the sendpacket address, when trying to unload the dll with freeLibrary. But apparently no oO

edit : My fault... got this code from a tuto without double checking the for loop
Code:
for(; isMoreMods && !isFound; isMoreMods = Module32Next(hSnapshot, &me))
			isFound = (_strcmpi(me.szModule, fnDll) == 0 || _strcmpi(me.szExePath, fnDll) == 0);
The noob that wrote this tuto aparently never tested his code cause this makes unload the next dll intead of our dll...

edit 2: Finally got it : my dll can hook the send packet at the start of my injector app and unhook at the end of the app, removing the console and making all back to normal. Was a good practice for me, thanks again for the code and the idea .
AlainProvist is offline  
Thanks
1 User
Old 03/24/2013, 23:16   #9
 
elite*gold: 0
Join Date: Mar 2013
Posts: 4
Received Thanks: 1
Your welcome thank you both for the tips about injection.
Currently trying to find a way to get incoming packets, in their decrypted form of course
Salim* is offline  
Old 03/25/2013, 22:27   #10
 
elite*gold: 0
Join Date: Sep 2007
Posts: 136
Received Thanks: 145
So this is for perfect world, right?
zowex is offline  
Old 03/27/2013, 20:57   #11
 
elite*gold: 0
Join Date: Sep 2012
Posts: 279
Received Thanks: 13
what this does?
deltadagger is offline  
Reply

Tags
c++, detours, dll injection, sendpacket


Similar Threads Similar Threads
[Question again, sorry] is this bot with SendPacket data parser?
09/14/2012 - Cabal Online - 3 Replies
Hello there, Ladies and Gentlemen :) Sorry, noob here and need some direction!! :D PSCBots use SendPacket for bot? it's works without Gameguard ByPass? your help is greatly appreciated :handsdown: Thank you ^_^ ~Credits~ (Click their name to thank them!) PSCBots : nice auto bot
League of Legends detouring
06/11/2011 - General Coding - 3 Replies
huhu, ich schreibe gerade ein Programm (C#) für LoL, habe allerdings Probleme beim finden von einer Adresse einer Funktion. Bis jetzt injected mein Programm eine in VC++ geschriebene dll, in der soll später eine Funktion von LoL mittels detours 'gehookt' werden. Da das Problem nur einen minimalen Anteil meiner Anwendung betrifft, meines Erachtens jedoch einen enormen Leseaufwand bzw. Wissen/Know-How in dem Gebiet Reverse Engineering erfordert, möchte ich mir die Arbeit durch dieses...
C->S SendPacket Frage
09/13/2010 - Last Chaos - 0 Replies
hey, hab die sendpacket funktion ( bevor das packet encrypted wird ) gehooked, klappt auch ganz gut http://s1.directupload.net/images/100913/422dsl63 .png nur scheint die sendpacket funktion ziehmlich behindert aufgebaut zu sein ( wie der rest von last chaos.. ). wäre nett wenn jemand nen prototyp der funktion posten könnte, dann würde mir eine menge arbeit erspart bleiben ;) danke
Problems while detouring send() and recv().
02/28/2009 - General Coding - 5 Replies
Hi there, i've a problem. I'm not sure if i've done some misstakes. But every time i inject my dll the game will crash while i get or send a packet. Maybe someone can help me? I'll post the source code. #include <windows.h> #include "detours.h" #pragma comment(lib, "detours.lib") DWORD RecvOffset = 0x00D95060;



All times are GMT +1. The time now is 12:57.


Powered by vBulletin®
Copyright ©2000 - 2026, Jelsoft Enterprises Ltd.
SEO by vBSEO ©2011, Crawlability, Inc.
This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

Support | Contact Us | FAQ | Advertising | Privacy Policy | Terms of Service | Abuse
Copyright ©2026 elitepvpers All Rights Reserved.