Nostale emulator state and reverse engineering ?

02/20/2015 16:48 SgT-Fatality#1
Hi,

I'm new in Nostale emulation and I would like to know what is the current developpement state ? Like what is done. Do we know the basic packet structure and stuff ?

Is there anyone who already worked on reverse engineering the client ?

Thanks a lot,
Sgt
02/20/2015 17:00 ernilos#2
Packet crypto has been released on C++ two years ago thought, also packetloggers are easy to find.

And... Seems to be a malediction to emulators, everyone who worked on it left the project after few months I:
02/20/2015 19:30 FI0w#3
Quote:
Originally Posted by ernilos View Post
Packet crypto(Yes but buggy) has been released on C++ two years ago thought, also packetloggers are easy to find.

And... Seems to be a malediction to emulators, everyone who worked on it left the project after few months I:
The Crypto~
02/20/2015 21:07 ernilos#4
Only decrypt long packets from client was buggy, but thought someone fixxed it lol
02/21/2015 15:08 *-OMG-*#5
Quote:
Originally Posted by ernilos View Post
Only decrypt long packets from client was buggy, but thought someone fixxed it lol
-- LOGIN: 100% Working Cryptography:

Code:
#ifndef CRYPTOGRAPHY_HPP
#define CRYPTOGRAPHY_HPP

class Cryptography
{
public:
	static std::string DecryptPacket(std::string packet, const std::size_t length);
	static std::string DecryptPassword(std::string password);
	static std::string EncryptPacket(std::string packet);
};

#endif
Code:
#include <sstream>

#include "cryptography.hpp"

std::string Cryptography::DecryptPacket(std::string packet, const std::size_t length)
{
	for (std::size_t i = 0; i < length; i++)
		packet[i] = (packet[i] - 0x0F) ^ 0x0C3;
	return packet;
}

std::string Cryptography::DecryptPassword(std::string password)
{
	std::size_t remaining = password.length() % 4;
	password = password.erase(0, !remaining ? 4 : remaining);
	for (std::size_t i = 0; i < password.length(); i++)
		password = password.erase(i, 1);
	for (std::size_t i = 2; i < password.length(); i += 3)
		password.insert(i, " ");
	std::stringstream ss(password);
	password.clear();
	for (std::size_t i = 0; ss >> std::hex >> i;)
		password.push_back(i);
	return password;
}

std::string Cryptography::EncryptPacket(std::string packet)
{
	for (std::size_t i = 0; i < packet.length(); i++)
		packet[i] += 0x0F;
	return packet;
}
-- WORLD: 100% Working Cryptography:

Code:
#pragma once

class TCryptography
{
public:
	static std::string DecryptSessionPacket(const std::string packet);
	static unsigned char GetEndByte(const unsigned short SessionKey);
	static std::string DecryptWorldPacket(const std::string packet, const std::size_t length, const unsigned short SessionKey);
	static std::string DecryptWorldPacket(const unsigned char packet[]);
	static std::string EncryptWorldPacket(std::string packet);
};
Code:
#include "TCryptography.hpp"

std::string TCryptography::DecryptSessionPacket(const std::string packet)
{
	std::string decryptedPacket;

	unsigned char current = NULL;

	for (std::size_t i = 1; i < packet.length() - 1; i++)
	{
		current = (((unsigned char)packet[i] - 0x0F) & 0xF0) >> 4;

		switch (current)
		{
		case 0:
			decryptedPacket += 0x20;
			break;
		case 1:
			decryptedPacket += 0x20;
			break;
		case 2:
			decryptedPacket += 0x2D;
			break;
		case 3:
			decryptedPacket += 0x2E;
			break;
		default:
			decryptedPacket += current + 0x2C;
			break;
		}

		current = ((unsigned char)packet[i] - 0x0F) - (current << 4);

		switch (current)
		{
		case 0:
			decryptedPacket += 0x20;
			break;
		case 1:
			decryptedPacket += 0x20;
			break;
		case 2:
			decryptedPacket += 0x2D;
			break;
		case 3:
			decryptedPacket += 0x2E;
			break;
		default:
			decryptedPacket += current + 0x2C;
			break;
		}
	}

	return decryptedPacket;
}

unsigned char TCryptography::GetEndByte(const unsigned short SessionKey)
{
	unsigned char c = (((SessionKey >> 6) & 0xFF) & 0x80000003);

	if (c < NULL)
	{
		c = (((c - 1) | 0xFFFFFFFC) + 1);
	}

	switch (c)
	{
	case 0:
		return 0xFF + ((SessionKey & 0xFF) + 0x40);
	case 1:
		return 0xFF - ((SessionKey & 0xFF) + 0x40);
	case 2:
		return (0xFF ^ 0xC3) + ((SessionKey & 0xFF) + 0x40);
	case 3:
		return (0xFF ^ 0xC3) - ((SessionKey & 0xFF) + 0x40);
	default:
		return (char)0x10E;
	}
}

std::string TCryptography::DecryptWorldPacket(const std::string packet, const std::size_t length, const unsigned short SessionKey)
{
	unsigned char c = (((SessionKey >> 6) & 0xFF) & 0x80000003);

	if (c < NULL)
	{
		c = (((c - 1) | 0xFFFFFFFC) + 1);
	}

	std::string decryptedPacket;

	unsigned char key = (SessionKey & 0xFF) + 0x40;

	switch (c)
	{
	case 0:
		for (std::size_t i = 0; i < length; i++)
		{
			decryptedPacket += (unsigned char)packet[i] - key;
		}
		break;
	case 1:
		for (std::size_t i = 0; i < length; i++)
		{
			decryptedPacket += (unsigned char)packet[i] + key;
		}
		break;
	case 2:
		for (std::size_t i = 0; i < length; i++)
		{
			decryptedPacket += ((unsigned char)packet[i] - key) ^ 0xC3;
		}
		break;
	case 3:
		for (std::size_t i = 0; i < length; i++)
		{
			decryptedPacket += ((unsigned char)packet[i] + key) ^ 0xC3;
		}
		break;
	default:
		decryptedPacket += 0x0F;
		break;
	}

	std::vector<std::string> vector;
	boost::algorithm::split(vector, decryptedPacket, std::bind2nd(std::equal_to<unsigned char>(), (0xFF)));

	decryptedPacket = "";
	for (std::size_t i = 0; i < vector.size(); i++)
		decryptedPacket += DecryptWorldPacket((unsigned char*)vector[i].c_str());

	return decryptedPacket;
}

std::string TCryptography::DecryptWorldPacket(const unsigned char packet[])
{
	const char table[] = { ' ', '-', '.', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'n' };

	unsigned char length = NULL, high = NULL, low = NULL;

	std::string decryptedPacket;

	for (std::size_t i = 0; i < strlen((char*)packet); i++)
	{
		if (packet[i] <= 0x7A)
		{
			length = packet[i];

			for (unsigned char j = 0; j < length; j++)
				decryptedPacket += packet[++i] ^ 0xFF;
		}
		else
		{
			length = packet[i] & 0x7F;

			for (unsigned char j = 0; j < length;)
			{
				high = (packet[++i] & 0xF0) >> 4;
				low = packet[i] & 0x0F;

				if (high != NULL && high != 0x0F)
				{
					decryptedPacket += table[high - 1];
					j++;
				}

				if (low != NULL && low != 0x0F)
				{
					decryptedPacket += table[low - 1];
					j++;
				}
			}
		}
	}

	return decryptedPacket;
}

std::string TCryptography::EncryptWorldPacket(std::string packet)
{
	std::string encryptedPacket;

	std::vector<std::string> vector;
	boost::algorithm::split(vector, packet, std::bind2nd(std::equal_to<unsigned char>(), (0x20)));

	for (std::size_t i = 0; i < vector.size(); i++)
	{
		if (i > 0)
		{
			encryptedPacket += vector[i].length() + 1;
			encryptedPacket += (char)0xDF;
		}
		else
		{
			encryptedPacket += vector[i].length();
		}

		for (std::size_t t = 0; t < vector[i].length(); t++)
			encryptedPacket += vector[i][t] ^ 0xFF;
	}
	return encryptedPacket;
}