You last visited: Today at 22:25
Advertisement
[Release] NosTale Vendetta pre/post Packet Cryption
Discussion on [Release] NosTale Vendetta pre/post Packet Cryption within the Nostale forum part of the MMORPGs category.
03/09/2019, 21:27
#1
elite*gold: 64
Join Date: May 2011
Posts: 1,229
Received Thanks: 854
[Release] NosTale Vendetta pre/post Packet Cryption
Hello NosTale Community,
some days ago I reversed the new "cryption" of Vendetta.
Actually it is just a simple xor with a table.
How it works:
When Client sends a packet:
- Crypt the packet as always (standard online encryption login & game)
- Xor the encrypted packet
When Client receives a packet:
- Xor the received encrypted packet
- Uncrypt the packet as always (standard online encryption login & game)
They use two different tables for sent and received packets.
In the attachment is the xorTable file. (Every table has a size of 0x10000.)
I wrote two classes for C++ & C#:
You need to call the initialize function (Best in the main/startup function of your application):
Code:
CNTXor::Initialize()
NTXor.h (Header File)
Code:
#pragma once
#define TABLE_SIZE 0x10000
class CNTXor
{
public:
CNTXor(bool i_fIsEncrypt);
virtual ~CNTXor() = default;
public:
static void Initialize();
public:
void crypt(char* i_pBuffer, size_t i_nLength);
void reset() {
this->m_nTableIndex = 0;
}
private:
bool m_fIsEncrypt;
size_t m_nTableIndex;
static bool s_fIsInitialized;
static char s_aEncryptTable[];
static char s_aDecryptTable[];
};
NTXor.cpp
Code:
#include "NTXor.h"
#include <fstream>
#include <stdexcept>
bool CNTXor::s_fIsInitialized = false;
char CNTXor::s_aEncryptTable[TABLE_SIZE];
char CNTXor::s_aDecryptTable[TABLE_SIZE];
CNTXor::CNTXor(bool i_fIsEncrypt)
: m_fIsEncrypt(i_fIsEncrypt), m_nTableIndex(0)
{
}
void CNTXor::Initialize()
{
if (s_fIsInitialized) {
return;
}
std::ifstream oXorTable("xorTable", std::ios::binary);
if (!oXorTable.is_open()) {
throw std::runtime_error("Couldn't find file 'xorTable'. Make sure to place it in the same directory as the binaries.");
}
oXorTable.read(s_aEncryptTable, TABLE_SIZE);
oXorTable.read(s_aDecryptTable, TABLE_SIZE);
oXorTable.close();
s_fIsInitialized = true;
}
void CNTXor::crypt(char* i_pBuffer, size_t i_nLength)
{
if (!s_fIsInitialized) {
throw std::runtime_error("XorTable is not initialized!");
}
for (size_t i = 0; i < i_nLength; i++) {
i_pBuffer[i] ^= (this->m_fIsEncrypt ? s_aEncryptTable[this->m_nTableIndex % TABLE_SIZE] : s_aDecryptTable[this->m_nTableIndex % TABLE_SIZE]);
this->m_nTableIndex++;
}
}
NTXor.cs
Code:
public class NTXor
{
private static readonly byte[] TableEncrypt = null;
private static readonly byte[] TableDecrypt = null;
private int _tableIndex;
private readonly bool _isEncrypt;
static NTXor()
{
using (var binaryReader = new BinaryReader(File.Open("xorTable", FileMode.Open)))
{
var length = (int)binaryReader.BaseStream.Length;
TableEncrypt = binaryReader.ReadBytes(length / 2);
TableDecrypt = binaryReader.ReadBytes(length / 2);
}
}
public NTXor(bool isEncrypt)
{
this._isEncrypt = isEncrypt;
}
public void Crypt(ref byte[] packet, int size = -1)
{
if (size == -1)
{
size = packet.Length;
}
for (var i = 0; i < size; i++)
{
if (_isEncrypt)
{
packet[i] ^= TableEncrypt[_tableIndex % TableEncrypt.Length];
}
else
{
packet[i] ^= TableDecrypt[_tableIndex % TableEncrypt.Length];
}
_tableIndex++;
}
}
public void Reset()
{
_tableIndex = 0;
}
}
Important: You have to create the class two times. The constructor accepts a boolean value. So true/false.
true = Encrypt
false = Decrypt
And you have to call reset when you connect to a new server.
C++ Test if your setup is correct (You should see at the end "Same! Crypt was successful")
Code:
#include <iostream>
#include <string>
#include <iomanip>
#include "NTXor.h"
int main()
{
char szPacket[] = { 0x9C, 0xBB, 0x9F, 0x02, 0x05, 0x03, 0x05, 0xF2, 0x0A, 0x00, 0x01, 0x09, 0x02, 0x05, 0x02, 0xF2, 0xC6, 0xB5, 0xBF, 0xC6, 0xF2, 0xFF, 0x03, 0x05, 0x03, 0xFF, 0x06, 0x06, 0x04, 0xFF, 0x05, 0x01, 0x03, 0x05, 0xFF, 0xFF, 0x03, 0x06, 0x06, 0xF2, 0x02, 0x02, 0x02, 0x06, 0x00, 0x05, 0x95, 0xFF, 0xD7, 0x01, 0xFC, 0x02, 0xFC, 0x02, 0xFC, 0xFF, 0x00, 0xF2, 0x02, 0xF2, 0xFF, 0x8F, 0x8F, 0xFF, 0x00, 0x05, 0xFF, 0x04, 0x94, 0x96, 0x01, 0x05, 0x06, 0x04, 0x8F, 0x96, 0x03, 0x95, 0x02, 0x01, 0x09, 0x09, 0x96, 0x91, 0x95, 0x01, 0x09, 0xFF, 0x05, 0x05, 0x04, 0xFF, 0xD8 };
const char szCrypted[] = { 0x01, 0xCA, 0xAD, 0x68, 0x12, 0xE5, 0x41, 0x55, 0x6B, 0xDC, 0xEF, 0x54, 0x0D, 0x6C, 0x35, 0x95, 0x14, 0x9A, 0x41, 0xAD, 0x3C, 0xDF, 0x48, 0x80, 0xF3, 0x51, 0x2D, 0x8F, 0xFB, 0x86, 0xCB, 0xA4, 0x57, 0x0D, 0x30, 0x04, 0xA1, 0x0A, 0x18, 0x15, 0xDE, 0x87, 0xF5, 0x5B, 0xAC, 0x23, 0xC8, 0x6D, 0xCE, 0x48, 0x57, 0x61, 0x7F, 0xC6, 0x30, 0x18, 0x8F, 0x84, 0xBD, 0xD1, 0x36, 0xEB, 0x47, 0x28, 0x03, 0x50, 0x61, 0x9F, 0x9A, 0x31, 0xBB, 0xD0, 0x68, 0x5F, 0x80, 0x60, 0x61, 0x04, 0x03, 0x8F, 0x58, 0x36, 0x6A, 0x2E, 0x7F, 0xBF, 0x0B, 0xCD, 0x77, 0x1B, 0xDB, 0x3A, 0x0F };
CNTXor::Initialize();
CNTXor ntXor(true);
ntXor.crypt(szPacket, sizeof(szPacket));
bool fIsSame = true;
for (int i = 0; i < sizeof(szPacket); i++) {
if (szPacket[i] != szCrypted[i]) {
std::cout << std::dec << std::setw(2) << std::setfill(' ') << i << " is different! " << std::hex << std::setw(2) << std::setfill('0') << (short(szPacket[i]) & 0xFF) << ":" << std::setw(2) << std::setfill('0') << (short(szCrypted[i]) & 0xFF) << std::endl;
fIsSame = false;
}
}
std::cout << (fIsSame ? "Same! Crypt was successful" : "Not same! Something went wrong.");
std::cin.get();
}
Code:
global NTXor encrypt(true);
global NTXor decrypt(false);
startup() {
CNTXor::Initialize(); // This line you need only in C++, C# does this automatically.
string packet = "packet to server";
// When LoginServer
Cryptography::EncryptLoginPacket(packet);
// When GameServer
Cryptography::EncryptGamePacket(packet);
// Vendetta only
encrypt.Crypt(packet, packet.length);
}
// When you connected to a new endpoint
onConnected() {
encrypt.Reset();
decrypt.Reset();
}
// When new incoming packet
packetReceived(buffer, size) {
// Vendetta only
decrypt.Crypt(buffer, size);
// When LoginServer
Cryptography::DecryptLoginPacket(buffer, size);
// When GameServer
Cryptography::DecryptGamePacket(buffer, size);
}
That's actually it.
I Hope it's useful for someone.
Average reverse time: 3h. Was a lot of confusing bullshit asm code.
#Edit: Fixed C++ Class. (used "i" instead of "m_nTableIndex")
Attached Files
xorTable.rar
(128.1 KB, 46 views)
03/10/2019, 00:58
#2
elite*gold: 0
Join Date: Sep 2015
Posts: 482
Received Thanks: 532
Good job Bash. You will surely defeat NosTale hacking section with a Xor table. :rofl:
03/10/2019, 02:15
#3
elite*gold: 50
Join Date: Jul 2014
Posts: 1,699
Received Thanks: 1,165
Quote:
Originally Posted by
BladeTiger12
Hello NosTale Community,
some days ago I reversed the new "cryption" of Vendetta.
Actually it is just a simple xor with a table.
How it works:
When Client sends a packet:
- Crypt the packet as always (standard online encryption login & game)
- Xor the encrypted packet
When Client receives a packet:
- Xor the received encrypted packet
- Uncrypt the packet as always (standard online encryption login & game)
They use two different tables for sent and received packets.
In the attachment is the xorTable file. (Every table has a size of 0x10000.)
I wrote two classes for C++ & C#:
You need to call the initialize function (Best in the main/startup function of your application):
Code:
CNTXor::Initialize()
NTXor.h (Header File)
Code:
#pragma once
#define TABLE_SIZE 0x10000
class CNTXor
{
public:
CNTXor(bool i_fIsEncrypt);
virtual ~CNTXor() = default;
public:
static void Initialize();
public:
void crypt(char* i_pBuffer, size_t i_nLength);
void reset() {
this->m_nTableIndex = 0;
}
private:
bool m_fIsEncrypt;
size_t m_nTableIndex;
static bool s_fIsInitialized;
static char s_aEncryptTable[];
static char s_aDecryptTable[];
};
NTXor.cpp
Code:
#include "NTXor.h"
#include <fstream>
#include <stdexcept>
bool CNTXor::s_fIsInitialized = false;
char CNTXor::s_aEncryptTable[TABLE_SIZE];
char CNTXor::s_aDecryptTable[TABLE_SIZE];
CNTXor::CNTXor(bool i_fIsEncrypt)
: m_fIsEncrypt(i_fIsEncrypt), m_nTableIndex(0)
{
}
void CNTXor::Initialize()
{
if (s_fIsInitialized) {
return;
}
std::ifstream oXorTable("xorTable", std::ios::binary);
if (!oXorTable.is_open()) {
throw std::runtime_error("Couldn't find file 'xorTable'. Make sure to place it in the same directory as the binaries.");
}
oXorTable.read(s_aEncryptTable, TABLE_SIZE);
oXorTable.read(s_aDecryptTable, TABLE_SIZE);
oXorTable.close();
s_fIsInitialized = true;
}
void CNTXor::crypt(char* i_pBuffer, size_t i_nLength)
{
if (!s_fIsInitialized) {
throw std::runtime_error("XorTable is not initialized!");
}
for (size_t i = 0; i < i_nLength; i++) {
i_pBuffer[i] ^= (this->m_fIsEncrypt ? s_aEncryptTable[this->m_nTableIndex % TABLE_SIZE] : s_aDecryptTable[this->m_nTableIndex % TABLE_SIZE]);
this->m_nTableIndex++;
}
}
NTXor.cs
Code:
public class NTXor
{
private static readonly byte[] TableEncrypt = null;
private static readonly byte[] TableDecrypt = null;
private int _tableIndex;
private readonly bool _isEncrypt;
static NTXor()
{
using (var binaryReader = new BinaryReader(File.Open("xorTable", FileMode.Open)))
{
var length = (int)binaryReader.BaseStream.Length;
TableEncrypt = binaryReader.ReadBytes(length / 2);
TableDecrypt = binaryReader.ReadBytes(length / 2);
}
}
public NTXor(bool isEncrypt)
{
this._isEncrypt = isEncrypt;
}
public void Crypt(ref byte[] packet, int size = -1)
{
if (size == -1)
{
size = packet.Length;
}
for (var i = 0; i < size; i++)
{
if (_isEncrypt)
{
packet[i] ^= TableEncrypt[_tableIndex % TableEncrypt.Length];
}
else
{
packet[i] ^= TableDecrypt[_tableIndex % TableEncrypt.Length];
}
_tableIndex++;
}
}
public void Reset()
{
_tableIndex = 0;
}
}
Important: You have to create the class two times. The constructor accepts a boolean value. So true/false.
true = Encrypt
false = Decrypt
And you have to call reset when you connect to a new server.
C++ Test if your setup is correct (You should see at the end "Same! Crypt was successful")
Code:
#include <iostream>
#include <string>
#include <iomanip>
#include "NTXor.h"
int main()
{
char szPacket[] = { 0x9C, 0xBB, 0x9F, 0x02, 0x05, 0x03, 0x05, 0xF2, 0x0A, 0x00, 0x01, 0x09, 0x02, 0x05, 0x02, 0xF2, 0xC6, 0xB5, 0xBF, 0xC6, 0xF2, 0xFF, 0x03, 0x05, 0x03, 0xFF, 0x06, 0x06, 0x04, 0xFF, 0x05, 0x01, 0x03, 0x05, 0xFF, 0xFF, 0x03, 0x06, 0x06, 0xF2, 0x02, 0x02, 0x02, 0x06, 0x00, 0x05, 0x95, 0xFF, 0xD7, 0x01, 0xFC, 0x02, 0xFC, 0x02, 0xFC, 0xFF, 0x00, 0xF2, 0x02, 0xF2, 0xFF, 0x8F, 0x8F, 0xFF, 0x00, 0x05, 0xFF, 0x04, 0x94, 0x96, 0x01, 0x05, 0x06, 0x04, 0x8F, 0x96, 0x03, 0x95, 0x02, 0x01, 0x09, 0x09, 0x96, 0x91, 0x95, 0x01, 0x09, 0xFF, 0x05, 0x05, 0x04, 0xFF, 0xD8 };
const char szCrypted[] = { 0x01, 0xCA, 0xAD, 0x68, 0x12, 0xE5, 0x41, 0x55, 0x6B, 0xDC, 0xEF, 0x54, 0x0D, 0x6C, 0x35, 0x95, 0x14, 0x9A, 0x41, 0xAD, 0x3C, 0xDF, 0x48, 0x80, 0xF3, 0x51, 0x2D, 0x8F, 0xFB, 0x86, 0xCB, 0xA4, 0x57, 0x0D, 0x30, 0x04, 0xA1, 0x0A, 0x18, 0x15, 0xDE, 0x87, 0xF5, 0x5B, 0xAC, 0x23, 0xC8, 0x6D, 0xCE, 0x48, 0x57, 0x61, 0x7F, 0xC6, 0x30, 0x18, 0x8F, 0x84, 0xBD, 0xD1, 0x36, 0xEB, 0x47, 0x28, 0x03, 0x50, 0x61, 0x9F, 0x9A, 0x31, 0xBB, 0xD0, 0x68, 0x5F, 0x80, 0x60, 0x61, 0x04, 0x03, 0x8F, 0x58, 0x36, 0x6A, 0x2E, 0x7F, 0xBF, 0x0B, 0xCD, 0x77, 0x1B, 0xDB, 0x3A, 0x0F };
CNTXor::Initialize();
CNTXor ntXor(true);
ntXor.crypt(szPacket, sizeof(szPacket));
bool fIsSame = true;
for (int i = 0; i < sizeof(szPacket); i++) {
if (szPacket[i] != szCrypted[i]) {
std::cout << std::dec << std::setw(2) << std::setfill(' ') << i << " is different! " << std::hex << std::setw(2) << std::setfill('0') << (short(szPacket[i]) & 0xFF) << ":" << std::setw(2) << std::setfill('0') << (short(szCrypted[i]) & 0xFF) << std::endl;
fIsSame = false;
}
}
std::cout << (fIsSame ? "Same! Crypt was successful" : "Not same! Something went wrong.");
std::cin.get();
}
Code:
global NTXor encrypt(true);
global NTXor decrypt(false);
startup() {
CNTXor::Initialize(); // This line you need only in C++, C# does this automatically.
string packet = "packet to server";
// When LoginServer
Cryptography::EncryptLoginPacket(packet);
// When GameServer
Cryptography::EncryptGamePacket(packet);
// Vendetta only
encrypt.Crypt(packet, packet.length);
}
// When you connected to a new endpoint
onConnected() {
encrypt.Reset();
decrypt.Reset();
}
// When new incoming packet
packetReceived(buffer, size) {
// Vendetta only
decrypt.Crypt(buffer, size);
// When LoginServer
Cryptography::DecryptLoginPacket(buffer, size);
// When GameServer
Cryptography::DecryptGamePacket(buffer, size);
}
That's actually it.
I Hope it's useful for someone.
Average reverse time: 3h. Was a lot of confusing bullshit asm code.
#Edit: Fixed C++ Class. (used "i" instead of "m_nTableIndex")
Nice work <3
I tried it and it works fine.
03/11/2019, 08:28
#4
elite*gold: 0
Join Date: Jul 2018
Posts: 10
Received Thanks: 1
Can you create bot for vendetta?
03/11/2019, 13:46
#5
elite*gold: 64
Join Date: May 2011
Posts: 1,229
Received Thanks: 854
Quote:
Originally Posted by
asasyn495
Can you create bot for vendetta?
Yes I can, for Sure. Which functions do you need?
03/11/2019, 20:16
#6
elite*gold: 0
Join Date: Jul 2018
Posts: 10
Received Thanks: 1
All you can do
03/11/2019, 21:06
#7
elite*gold: 50
Join Date: Jul 2014
Posts: 1,699
Received Thanks: 1,165
Quote:
Originally Posted by
asasyn495
All you can do
I think he said it as a Joke...
06/30/2019, 13:38
#8
elite*gold: 0
Join Date: Apr 2018
Posts: 85
Received Thanks: 78
Good job bro
Similar Threads
[Selling] Origin ACC (BF3-Pre/BF4-Pre/BFH-Pre)
09/28/2015 - Origin Trading - 2 Replies
Wie es am titel geschrieben ist verkaufe ich meinen origin account mit all battlefield spielen premium activated.
der preis ist 40euro uber paypal. fur details bitte anschreiben.
- Im selling currently my origin account with the games
battlefield 3 premuim
battlefield 4 premuim
battlefield hardline premium
the price is 55euro via paypal. for further details please write a comment or pn
[Small Release] (VSRO) Skilldataenc (de)cryption
09/03/2012 - SRO PServer Guides & Releases - 8 Replies
Released on RZ a week ago, giving it a shot at epvp aswell. Hope some people find this useful.
Credits to Schickl aswell in helping :handsdown:
Original RZ Post:
Packet Cryption :]
12/19/2007 - Metin2 - 126 Replies
Hi @ all
Ich suche ein paar leute die bissel ahnung von Delphi, C++ und Packets haben.Zu mir ich habe einige erfahrungen mit Packets in dem Spiel KalOnline gemacht und habe dort auch schon die alte Packet Cryption (die seit einer weile auch Public ist geknackt) nun möchte ich die Packet Cryption von Metin 2 knacken :]
Da meine Delphi skills nicht alzugut sind brauche ich leute die schon seit längerem Delphi oder C++ programmieren falls ASM skills vorhanden noch besser.
Ich kenne mehrere...
All times are GMT +1. The time now is 22:31 .