Скрипт, который декодирует файлы клиента (RSA и gzip). Аналог l2encdec.
В интернете описания алгоритма не нашел, поэтому пришлось разбираться самому (плюс искать ключи). Ставил хуки на gmpz_powm и gmpz_export в libgmp-3, смотрел что передает и получает l2encdec.
Если бы люди не зажимали информацию (тогда, когда это не бьет по карману), то все бы мы тратили намного меньше времени впустую.
О чем я говорю: http://www.l2wh.com/forum/showthread.php?t=1903
Нельзя было просто скопировать ключи?) Теперь мы должны искать бинарник за 24-01-2008. И речь ведь не о исходниках l2encdec.
PHP код:
<?php
/**
* L2 file decoder (4 october 2011).
* @author Hint aka Ilya
*/
function decode($filename, $original = true)
{
$file = @file_get_contents($filename);
if (!$file) return false;
if (strlen($file) < 28 + 128) return false;
$head = mb_convert_encoding(substr($file, 0, 28), 'UTF-8', 'UTF-16LE');
if ($head != 'Lineage2Ver413') return false;
Hint, ну тыб тут спросил, я бы выложил сорци своего недоделанного аналога l2encdec, и кстати для его написания мне публично доступной инфы из инета вполне хватило
вот мой модуль для шифрования:
delphi Код:
unit l2CryptRSA;
interfaceprocedure DecodeRSA(var data; const size: Integer);
procedure EncodeRSA(var data; const size: Integer);
function DecryptStr413(const data: string): string;
implementationuses
ZLibEx;
const
bufLen = 128;
type
mpz_t = record
mp_alloc,
mp_size: Integer;
mp_d: Pointer;
end;
TRSABlocks = array[0..0] of array[1..bufLen] ofByte;
const//priv. exponent (d)
priv_key: array[0..127] ofChar =
#$65#$DE#$C1#$81#$50#$95#$1E#$C9#$3E#$22#$DB#$C7#$16#$B8#$2D#$6F+
#$FC#$E2#$46#$F7#$53#$85#$A2#$5C#$FE#$5D#$AD#$18#$76#$95#$A1#$31+
#$B6#$C1#$93#$D4#$CB#$62#$15#$8C#$9A#$DA#$6D#$3A#$25#$A7#$43#$4E+
#$F0#$C2#$14#$1C#$3D#$FE#$C6#$63#$82#$1F#$54#$AE#$D9#$43#$10#$83+
#$4D#$B3#$77#$0A#$E1#$2F#$35#$D7#$9D#$90#$F0#$72#$F2#$0B#$DD#$4C+
#$12#$5F#$1D#$9D#$64#$D2#$43#$66#$B8#$32#$7F#$A2#$FC#$F8#$07#$6A+
#$4C#$50#$5B#$40#$C4#$E6#$D3#$38#$78#$1D#$29#$00#$E4#$76#$97#$71+
#$1E#$84#$8E#$3C#$06#$75#$5C#$14#$86#$70#$D4#$98#$D7#$C2#$B4#$30;
e: mpz_t = (mp_alloc: 32; mp_size: 32; mp_d: @priv_key[0]);
//modulo (n)
modulo: array[0..127] ofChar =
#$39#$20#$AE#$94#$60#$C6#$D4#$13#$64#$D2#$93#$AA#$A3#$C6#$A4#$C3+
#$67#$AE#$69#$D0#$B3#$C3#$67#$B5#$AB#$81#$88#$10#$D2#$F1#$7A#$70+
#$E3#$5D#$20#$AE#$5B#$B6#$7B#$D8#$04#$56#$C8#$67#$C2#$29#$01#$07+
#$19#$93#$30#$43#$FA#$ED#$79#$46#$3E#$2F#$C0#$B1#$4E#$43#$D9#$1F+
#$FD#$9B#$F6#$83#$0A#$89#$C0#$72#$7D#$5D#$C5#$95#$34#$32#$16#$8F+
#$C1#$A5#$B1#$7B#$C8#$91#$CE#$A1#$3D#$65#$B3#$88#$62#$44#$93#$55+
#$63#$57#$87#$9B#$AF#$6D#$55#$89#$E2#$B1#$B8#$55#$FC#$09#$2E#$3D+
#$F4#$69#$58#$12#$CF#$1A#$8A#$06#$44#$65#$01#$5C#$DE#$D6#$B4#$75;
m: mpz_t = (mp_alloc: 32; mp_size: 32; mp_d: @modulo[0]);
//pub. exponent (e)
pub_key = $1d;
gmpdll = 'libgmp-3.dll';
procedure mpz_init(var Dest: mpz_t); cdecl;
external gmpdll name '__gmpz_init';
procedure mpz_clear(var Dest: mpz_t); cdecl;
external gmpdll name '__gmpz_clear';
procedure mpz_powm(var Dest: mpz_t; const Base, Exponent, Modulus: mpz_t); cdecl;
external gmpdll name '__gmpz_powm';
procedure mpz_powm_ui(var Dest: mpz_t; var Base: mpz_t; Exponent: Cardinal;
const Modulus: mpz_t); cdecl;
external gmpdll name '__gmpz_powm_ui';
procedure mpz_import(var rop: mpz_t; count, order, size, endian,
nails: Cardinal; const op); cdecl;
external gmpdll name '__gmpz_import';
procedure mpz_export(var rop, count; order, size, endian,
nails: Cardinal; const op: mpz_t); cdecl;
external gmpdll name '__gmpz_export';
var
r,d: mpz_t;
procedure RSA_BlockDec(var data);
var
count: Cardinal;
begin
mpz_import(d,bufLen,1,1,0,0,data);
mpz_powm_ui(r,d,$1d,m);
count:=32;
mpz_export(data,count,1,4,1,0,r);
end;
procedure RSA_BlockEnc(var data);
var
count: Cardinal;
begin
mpz_import(d,bufLen,1,1,0,0,data);
mpz_powm(r,d,e,m);
count:=32;
mpz_export(data,count,1,4,1,0,r);
end;
procedure DecodeRSA(var data; const size: Integer);
var
i: Integer;
dt: TRSABlocks absolute data;
beginfor i:=0to size div bufLen - 1do RSA_BlockDec(dt[i]);
end;
procedure EncodeRSA(var data; const size: Integer);
var
i: Integer;
dt: TRSABlocks absolute data;
beginfor i:=0to size div bufLen - 1do RSA_BlockEnc(dt[i]);
end;
function UnPack(const data; const size: Integer): string;
var
i,k: Integer;
dt: TRSABlocks absolute data;
begin
Result:='';
for i:=0to size div bufLen - 1dobegin
k:=Length(Result);
SetLength(Result,k+dt[i][3]);
Move(dt[i][(128-dt[i][3])and $7C],Result[k+1],dt[i][3]);
end;
end;
function Pack(const data: string): string;
var
i,k: Integer;
begin{ TODO : create Pack function }end;
function Decompress(const data: string): string;
begin
Result:=ZDecompressStr(data);
end;
function DecryptStr413(const data: string): string;
begin
Result:=data;
DecodeRSA(Result[1],Length(Result));
Result:=Copy(UnPack(Result[1],Length(Result)),5,Length(Result));
Result:=Decompress(Result);
end;
initialization
mpz_init(d);
mpz_init(r);
finalization
mpz_clear(d);
mpz_clear(r);
end.
Добавлено через 3 минуты
Цитата:
Сообщение от xkor
и кстати для его написания мне публично доступной инфы из инета вполне хватило
а хотя не, вру, ключи я извлекал из l2encdec запустив на отладку через ollydbg
__________________
Я здесь практически не появляюсь!, Skype - ikskor
Последний раз редактировалось xkor, 04.10.2011 в 15:23.
Причина: Добавлено сообщение
Зато теперь есть общедоступная реализация на php и delphi :)
В интернете подробной информации нет. Про RSA понятно по l2encdec (вывод процесса распаковки). Сжатие - логично, потому что размер файла меньше (плюс DStuff написал про использование zlib у себя в USAGE). То, что сначала сжимают, а потом шифруют через RSA - тоже понятно (иначе бы ничего не сжималось :) Заголовок и CRC видно в hex-редакторе (размер остального кратен 128, что намекает на RSA и размер ключа и блоков).
Так что единственное темное пятно - ключи, а вот их нигде нет :)
Кстати, твой вариант не всегда будет работать, потому что в последнем блоке, который неполный, данные могут быть смещены (не знаю почему и зачем). Из-за этого пришлось добавить костыль:
Добавлено через 3 минуты
Честно говоря, копался в этом больше из-за любопытства, а не по необходимости. Началось с разбора нового 'itemname-*.dat' (l2disasm уже не помогает, поэтому пришлось писать свою программу), а потом захотелось разобраться и с l2encdec.
Последний раз редактировалось Hint, 04.10.2011 в 15:46.
Причина: Добавлено сообщение
Кстати, твой вариант не всегда будет работать, потому что в последнем блоке, который неполный, данные могут быть смещены (не знаю почему и зачем). Из-за этого пришлось добавить костыль:
я уже плохо помню (писал тот код года два назад), но по моему функция UnPack эту проблему решает
__________________
Я здесь практически не появляюсь!, Skype - ikskor
Пишу редактор файлов (dat,ini,int,thm) для новых хроник пока еще нет правильных ddf структур файлов, приходится разбирать в ручную. Может у кого есть чем поделиться и объединить усилия, так как много времени уходит на это.
Разбираю ItemName-ru.dat, и так понимаю аналогов функций в ddf нету.
Пишу редактор файлов (dat,ini,int,thm) для новых хроник пока еще нет правильных ddf структур файлов, приходится разбирать в ручную. Может у кого есть чем поделиться и объединить усилия, так как много времени уходит на это.
Разбираю ItemName-ru.dat, и так понимаю аналогов функций в ddf нету.
Да, l2disasm устарел. Можно обойтись ENBBY, но это ужасные костыли (и не работает, если число элементов в массиве увеличивается). Нужные новые сложные элементы, похожие на MAT, MTX. Да и вообще, таблица (текстовый файл с табуляциями) уже не подходит, нужен вывод в более сложном формате (например, xml). Лично я, когда начала работать с GoD, написал свой l2disasm и не жалею.
Ущербный DDF для ItemName, который на некоторых файлах работать не будет, если в них встречаются длинные многомерные массивы (не работал на PTS клиенте L2.ru из-за того, что в "кривом" описании одного предмета был массив из 50+ элементов):