Сообщений: 13
Тем: 3
Зарегистрирован: Aug 2016
Репутация:
203
Вдохновившись темой
https://forum.zone-game.info/showthread.php?t=40993 захотелось мне написать на коленке что-то вроде простенького редактора dat файлов, полноценного редактора конечно не получилось, но все же возможно найдутся люди кто подхватит идею
Итак, первым делом пришлось вытащить ключ из l2encdec, тут пришла на помощь IDA, открываю файл l2encdec.exe, декомпил в С код, долгий анализ и ничего не вышло, нету его там, но где то же он есть )) Открываю gg-bps.dll и вот она заветная строка
PHP код:
<?php
v3 = "75b4d6de5c016544068a1acf125869f43d2e09fc55b8b1e289556daf9b8757635593446288b3653da1ce91c87bb1a5c18f16323495c55"
"d7d72c0890a83f69bfd1fd9434eb1c02f3e4679edfa43309319070129c267c85604d87bb65bae205de3707af1d2108881abb567c3b3d0"
"69ae67c3a4c6a3aa93d26413d4c66094ae20390000001d";
Этих данных нам с головой хватит для дешифрации (Примечание, способ работает после прогона папки system утилитой patcher.exe)
Первые 256 байт это так называемый modulus, оставшиеся 8 байт это publicExponent (то что нужно для инициализации RSAPublicKeySpec)
Далее конечно же написание кода с использованием полученных ключей, что примечательно структура даток напоминает структуру пакетов, а именно ByteBuffer и все вытекающее, чтобы увидеть быстрый результат пришлось взять L2GameDataName.dat т.к. он состоит из списка простых строк
Код
PHP код:
<?php
import javax.crypto.Cipher;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.security.KeyFactory;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.RSAPublicKeySpec;
import java.util.zip.Inflater;
import java.util.zip.InflaterInputStream;
/**
BSmith
08.08.2016
*/
public class Test
{
public static void main(String[] args)
{
Cipher cipher;
try
{
cipher = Cipher.getInstance("RSA/ECB/nopadding");
RSAPublicKeySpec rsaPublicKeySpec = new RSAPublicKeySpec(new BigInteger("75B4D6DE5C016544068A1ACF125869F43D2E09FC55B8B1E289556DAF9B8757635593446288B3653DA1CE91C87BB1A5C18F16323495C55D7D72C0890A83F69BFD1FD9434EB1C02F3E4679EDFA43309319070129C267C85604D87BB65BAE205DE3707AF1D2108881ABB567C3B3D069AE67C3A4C6A3AA93D26413D4C66094AE2039", 16), new BigInteger("1d", 16));
RSAPublicKey rsaPublicKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(rsaPublicKeySpec);
cipher.init(Cipher.DECRYPT_MODE, rsaPublicKey);
}
catch(Exception e)
{
e.printStackTrace();
return;
}
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(128);
try(FileInputStream fileInputStream = new FileInputStream(new File("L2GameDataName.dat")))
{
fileInputStream.skip(28);
byte[] bytes = new byte[128];
int length = fileInputStream.available() - 20;
while(length > 0)
{
length -= fileInputStream.read(bytes);
byte[] doFinal = cipher.doFinal(bytes);
int size = doFinal[0x03];
size += doFinal[0x02] << 8 & 0x0000ff00;
size += doFinal[0x01] << 16 & 0x00ff0000;
size += doFinal[0x00] << 24 & 0xff000000;
int pad = -size & 0x01 + -size & 0x02;
byteArrayOutputStream.write(doFinal, 128 - size - pad, size);
}
bytes = byteArrayOutputStream.toByteArray();
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes, 4, bytes.length - 4);
InflaterInputStream inflaterInputStream = new InflaterInputStream(byteArrayInputStream, new Inflater());
byteArrayOutputStream = new ByteArrayOutputStream(128);
bytes = new byte[128];
while((length = inflaterInputStream.read(bytes)) > 0)
{
byteArrayOutputStream.write(bytes, 0, length);
}
ByteBuffer byteBuffer = ByteBuffer.wrap(byteArrayOutputStream.toByteArray());
int count = Integer.reverseBytes(byteBuffer.getInt());
for(int i = 0; i < count; i++)
{
System.out.println(readUtfString(byteBuffer));
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
public static String readUtfString(ByteBuffer buffer)
{
int size = Integer.reverseBytes(buffer.getInt());
byte[] bytes = new byte[size];
for(int i = 0; i < size; i += 2)
{
bytes[i + 1] = buffer.get();
bytes[i] = buffer.get();
}
try
{
return new String(bytes, "Unicode");
}
catch(Exception e)
{
return "Null";
}
}
}
И конечно же результат, точнее вырезки из лога
Результат
Упаковка: Улучш. Бронзовый Браслет (90 дн.)
Упаковка: Улучш. Стальной Браслет (1 день)
Упаковка: Улучш. Стальной Браслет (15 дн.)
Упаковка: Улучш. Стальной Браслет (30 дн.)
Упаковка: Улучш. Стальной Браслет (90 дн.)
Упаковка: Улучш. Мифриловый Браслет (1 день)
Упаковка: Улучш. Мифриловый Браслет (15 дн.)
LineageNpcsTex3.castle_enchanter.castle_enchanter_a_t01
LineageNpcsTex3.castle_healer.castle_healer_a_t00
LineageNpcsTex3.castle_healer.castle_healer_a_t01
LineageNpcsTex3.castle_summoner.castle_summoner_a_t00
LineageNpcsTex3.castle_summoner.castle_summoner_a_t01
LineageNpcsTex3.castle_summoner.castle_summoner_a_t02
LineageNpcsTex3.castle_summoner.castle_summoner_a_t03
LineageEffect.u_aga_pegasus_deco
icon.reward_02
Map_Arena
P.s. Подводя итоги можно с уверенностью сказать что основа для декодирования даток готова, далее необходимо собственно сделать поддержку структур нужных нам файлов а именно это
PHP код:
<?php
int count = Integer.reverseBytes(byteBuffer.getInt());
for(int i = 0; i < count; i++)
{
System.out.println(readUtfString(byteBuffer));
}