[Release] Sro++

08/14/2015 16:29 Iwa13#1
I've made compatible my old sro stuffs with vSro client 1.188 and coalesced into this small library. It provides hooking packet receive, sending packet and some utility functions.


Documentation


Example code:
Code:
#include "SroPP.h"
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>

void printUIText(const wchar_t* codename)
{
	wchar_t buffer[1024];
	swprintf_s(buffer, L"%s -> '%s'", codename, SroPP::Game::GetUIText(codename));
	SroPP::Game::WriteChat(SroPP::ChatGroup::GM, buffer, 255 << 8);
}

//copied from: https://github.com/ProjectHax/ServerStats/blob/master/ServerStats/shared/stream_utility.cpp
#include <sstream>
#include <cctype>
#include <iomanip>
std::string DumpToString(const void* stream, size_t size)
{
	std::stringstream ss;
	auto buffer = static_cast<const unsigned char*>(stream);
	int fields[16];
	size_t index = 0;
	size_t cur = 0;
	size_t total = size;
	if (total == 0 || total % 16)
	{
		total += (16 - (total % 16));
	}
	for (size_t x = 0; x < total; x++)
	{
		fields[index++] = cur < size ? buffer[x] : 0;
		++cur;
		if (index == 16)
		{
			for (size_t y = 0; y < 16; y++)
			{
				if (cur - 16 + y < size)
				{
					ss << std::hex << std::setfill('0') << std::setw(2) << fields[y] << ' ';
				}
				else
				{
					ss << "   ";
				}
			}
			ss << "   ";
			for (size_t y = 0; y < 16; y++)
			{
				if (cur - 16 + y < size)
				{
					int ch = fields[y];
					if (std::isprint(ch) && !std::isspace(ch))
					{
						ss << (char)ch;
					}
					else
					{
						ss << '.';
					}
				}
				else
				{
					ss << '.';
				}
			}
			ss << std::endl;
			index = 0;
		}
	}
	return ss.str();
}

void printPacketDump(const SroPP::Packet& packet)
{
	std::string dump;
	auto appendf = [&dump](const char* format, ...)
	{
		char buf[256];
		va_list ap;
		va_start(ap, format);
		vsprintf_s(buf, format, ap);
		va_end(ap);
		dump.append(buf);
	};

	appendf("[Opcode: %4X] [Size: %Iu bytes]\n", packet.Opcode(), packet.Size());

	char packetBuffer[256];
	size_t bytesToDump = (std::min)(packet.Size(), sizeof(packetBuffer));

	if (bytesToDump > 0)
	{
		packet.Peek(packetBuffer, bytesToDump);
		dump.append(DumpToString(packetBuffer, bytesToDump));
	}

	if (size_t remaining = packet.Size() - bytesToDump)
		appendf("... + %lu bytes\n", remaining);

	dump.append("\n");
	OutputDebugStringA(dump.c_str());
}

BOOL WINAPI DllMain(HMODULE hModule, DWORD dwReason, void*)
{
	if (dwReason == DLL_PROCESS_ATTACH)
	{
		DisableThreadLibraryCalls(hModule);
		try
		{
			SroPP::Library::BeginInitialize();
			SroPP::PacketHook::RegisterReceive([](const SroPP::Packet& packet) -> bool
			{
				printPacketDump(packet);
				switch (packet.Opcode())
				{
					case 0xb045:
					{
						bool succeed = packet.Read<bool>();
						if (succeed)
						{
							uint32_t uniqueId = packet.Read<uint32_t>();
							wchar_t buffer[256];
							swprintf_s(buffer, L"Selected target ID: %lu", uniqueId);
							SroPP::Game::WriteChat(SroPP::ChatGroup::All, buffer, 0xFF00D8D8);
						}
					}
					break;
					case 0x3026:
					{
						uint8_t type = packet.Read<uint8_t>();
						if (type == 1)
						{
							uint32_t sender = packet.Read<uint32_t>();
							auto message = packet.ReadStringA();
							if (message == ".1")
							{
								printUIText(L"UIIT_MSG_GUILD_JOIN_RESULT");
								printUIText(L"SN_TALK_QTUTORIAL_CH_27");
								printUIText(L"SN_MOB_CH_GYO_CLON");
							}
						}
					}
					break;
				}
				return false;
			});
			SroPP::Library::EndInitialize();
		}
		catch (std::exception &ex)
		{
			MessageBoxA(NULL, ex.what(), "exception", MB_ICONERROR);
		}
	}
	return TRUE;
}
Example code for appending data to end of the login packet:
Code:
std::vector<char> onLoginRequest()
{
#pragma pack(push, 1)
	struct
	{
		uint32_t val1;
	} s;
#pragma pack(pop)
	
	s.val1 = 0x12345678;

	return SroPP::MakeVector(s);
}

BOOL WINAPI DllMain(HMODULE hModule, DWORD dwReason, void*)
{
	if (dwReason == DLL_PROCESS_ATTACH)
	{
		DisableThreadLibraryCalls(hModule);
		try
		{
			SroPP::Library::BeginInitialize();
			SroPP::PacketHook::RegisterSendLoginRequest(onLoginRequest);
			SroPP::Library::EndInitialize();
		}
		catch (std::exception &ex)
		{
			MessageBoxA(NULL, ex.what(), "exception", MB_ICONERROR);
			return FALSE;
		}
	}
	return TRUE;
}
thanks to pushedx for his attentive helps
08/14/2015 19:50 qoaway#2
llgw ^^
08/14/2015 19:58 PortalDark#3
Moved to correct section
08/14/2015 20:07 Royalblade*#4
not bad dude.

Weeman released something very similar a few years back. Could've used that as a base.
08/15/2015 01:24 Gummieֆ'#5
What is this :)
08/15/2015 02:03 B1Q B0SS#6
good
08/15/2015 02:10 Sonic `#7
What does it do if i may ask :)
thanks for the respond, 2x_o0.
08/15/2015 12:10 qoaway#8
Quote:
Originally Posted by Aleჯco* View Post
What is this :)
Quote:
Originally Posted by Bobby` View Post
What does it do if i may ask :)
thanks for the respond, 2x_o0.

It's a cpp library which allows you make advanced client side edits for your private server
08/15/2015 14:31 Konami$#9
great
08/16/2015 14:32 Dracula Untold#10
Same question . what is this?
08/16/2015 14:36 LastThief*#11
If you don't know what is this, get out of the thread this isn't for you.
08/31/2015 13:43 EraSro#12
very useful thanks dude
09/01/2015 09:08 Iwa13#13
updated

Quote:
Ver 1.1
static std::vector<char> MakeVector(T &val)
-Serializes specified value to vector<char>

Arguments
val: Value to be serialized.
Templates
T: A non-pointer and pod type.
Quote:
Ver 1.1
static void RegisterSendLoginRequest<Func>(Func func)
Registers the function that will be called when login packet (0x6102) is written. Allows you to append custom data(e.g. HWID) to end of the login packet. If you previously registered a function, it will be replaced.

Arguments
func: A lambda/function that suitable for vector<char>() call.
Return value of "func" argument: The data that will be appended to end of the login packet (0x6102)
Quote:
Example code for appending data to end of the login packet:
Code:
std::vector<char> onLoginRequest()
{
#pragma pack(push, 1)
	struct
	{
		uint32_t val1;
	} s;
#pragma pack(pop)
	
	s.val1 = 0x12345678;

	return SroPP::MakeVector(s);
}

BOOL WINAPI DllMain(HMODULE hModule, DWORD dwReason, void*)
{
	if (dwReason == DLL_PROCESS_ATTACH)
	{
		DisableThreadLibraryCalls(hModule);
		try
		{
			SroPP::Library::BeginInitialize();
			SroPP::PacketHook::RegisterSendLoginRequest(onLoginRequest);
			SroPP::Library::EndInitialize();
		}
		catch (std::exception &ex)
		{
			MessageBoxA(NULL, ex.what(), "exception", MB_ICONERROR);
			return FALSE;
		}
	}
	return TRUE;
}
09/05/2015 01:04 farukdgn#14
Really great work, thanks!
09/11/2015 21:43 WeeMan1337#15
Quote:
Originally Posted by Royalblade* View Post
not bad dude.

Weeman released something very similar a few years back. Could've used that as a base.
I think you mean Drew. edxSilkroadLoader has some similarities as well as SilkMod.