ANTICHAT

ANTICHAT (https://forum.antichat.xyz/index.php)
-   С/С++, C#, Rust, Swift, Go, Java, Perl, Ruby (https://forum.antichat.xyz/forumdisplay.php?f=24)
-   -   Дешифратор файлов Lineage2 версии 111. С# (https://forum.antichat.xyz/showthread.php?t=792907)

BIT_hack 14.10.2024 10:20

Это мой первый опыт использования XOR и C#. Возможно, профессионалу мой код покажется не самым оптимальным, но он выполняет свою задачу.

У меня вопрос: как получить из текста "Lineage2Ver111" байты, которые будут такими же, как и из файла? Я не уверен, как это называется, но, по-моему, это связано с нулевыми байтами.

Например, в коде я получаю байты для текста "Lineage2Ver111": "4C 69 6E....". А в файле для этого же текста я получаю такие байты:"4C 00 69 00 6E....".

Я пробовал разные кодировки и много чего ещё, но не добавлять же после каждого байта нулевые байты. Я думаю, что в C# должна быть стандартная функция преобразования для этого.

Этот код представляет собой дешифратор файлов Lineage2 версии 111. на C#

Чтобы не тратить ваше время, сразу скажу, что этот код работает.

У меня только один вопрос, который я описал выше.

C#:


[CODE]
using
System
.
IO
;
public
static
class
Lineage2Decrypter
{
// Ключ XOR для Lineage2Ver111
private
const
byte
KeyXOR
=
0xAC
;
// Шаблон байтов для поиска начала зашифрованных данных Lineage2Ver111
private
static
readonly
byte
[
]
ByteVersion111
=
{
76
,
0
,
105
,
0
,
110
,
0
,
101
,
0
,
97
,
0
,
103
,
0
,
101
,
0
,
50
,
0
,
86
,
0
,
101
,
0
,
114
,
0
,
49
,
0
,
49
,
0
,
49
,
0
}
;
// Дешифрование файла Lineage2
public
static
string
L2DecodeU
(
string
fileName
)
{
if
(
!
File
.
Exists
(
fileName
)
)
return
fileName
;
byte
[
]
fileData
=
File
.
ReadAllBytes
(
fileName
)
;
int
startIndex
=
FindStringIndex
(
fileData
,
ByteVersion111
)
;
if
(
startIndex
>=
0
)
{
startIndex
+=
ByteVersion111
.
Length
;
byte
[
]
decryptedData
=
DecryptData
(
fileData
,
startIndex
,
KeyXOR
)
;
string
outputFilePath
=
"temp/dec-"
+
Path
.
GetFileName
(
fileName
)
;
Directory
.
CreateDirectory
(
Path
.
GetDirectoryName
(
outputFilePath
)
)
;
using
(
FileStream
outputFile
=
File
.
OpenWrite
(
outputFilePath
)
)
{
outputFile
.
Write
(
decryptedData
,
0
,
decryptedData
.
Length
)
;
}
return
outputFilePath
;
}
return
fileName
;
}
// Поиск начала зашифрованных данных в массиве байт
private
static
int
FindStringIndex
(
byte
[
]
data
,
byte
[
]
pattern
)
{
for
(
int
i
=
0
;
i

BIT_hack 14.10.2024 10:40

Если вам понадобится использовать этот код, вы можете сделать это следующим образом:

C#:


Код:

L2DecodeU
(
"interface.u"
)
;

После выполнения этой команды в текущей папке с программой появится папка temp, а в ней — файл dec-interface.u.

MrKirill1232 14.10.2024 10:53

Цитата:

Сообщение от BIT_hack

У меня вопрос: как получить из текста "Lineage2Ver111" байты, которые будут такими же, как и из файла? Я не уверен, как это называется, но, по-моему, это связано с нулевыми байтами.
Например, в коде я получаю байты для текста "Lineage2Ver111": "4C 69 6E....". А в файле для этого же текста я получаю такие байты:"4C 00 69 00 6E....".
Я пробовал разные кодировки и много чего ещё, но не добавлять же после каждого байта нулевые байты. Я думаю, что в C# должна быть стандартная функция преобразования для этого.

Текст
Код:

Lineage2Ver111
закодирован как UTF-16LE - где на 1 символ отводится 2 байта.

BIT_hack 14.10.2024 10:55

Цитата:

Сообщение от MrKirill1232

Текст
Код:

Lineage2Ver111
закодирован как UTF-16LE - где на 1 символ отводится 2 байта.

Я пробовал и так и так и в разных языках программирования но у меня все равно остаются нулевые байты(

Если есть возможно приведите свой код.

MrKirill1232 14.10.2024 10:58

Цитата:

Сообщение от BIT_hack

Я пробовал и так и так и в разных языках программирования но у меня все равно остаются нулевые байты(

Java:


Код:

public
final
static
String
LINEAGE_2_HEADER
=
"Lineage2Ver"
;
public
final
static
int
LINEAGE_2_HEADER_SIZE
=
(
LINEAGE_2_HEADER
.
length
(
)
*
2
)
+
(
3
*
2
)
;
private
CommonPair

getCryptVersion
(
File
inputFile
)
{
byte
[
]
headerAsBytes
=
readHeader
(
inputFile
)
;
if
(
headerAsBytes
.
length
==
0
)
{
return
null
;
}
final
String
headerAsString
=
new
String
(
headerAsBytes
,
StandardCharsets
.
UTF_16LE
)
;
if
(
headerAsString
.
startsWith
(
LINEAGE_2_HEADER
)
)
{
int
cryptVersion
=
Integer
.
parseInt
(
headerAsString
.
substring
(
LINEAGE_2_HEADER
.
length
(
)
)
)
;
if
(
!
(
cryptVersion
==
111
||
cryptVersion
==
121
)
)
{
return
null
;
}
switch
(
cryptVersion
)
{
case
111
:
{
return
new
CommonPair
<>
(
cryptVersion
,
-
1397969748
)
;
}
case
121
:
{
String
filename
=
getFileName
(
)
.
toLowerCase
(
Locale
.
ROOT
)
;
//_fileName.split("\\.")[_fileName.split("\\.").length - 1];
int
xor
=
0
;
for
(
int
index
=
0
;
index

(
cryptVersion
,
xor
)
;
}
}
}
return
null
;
}

Даже такой "жутко-код" выполнял свои функции.

BIT_hack 14.10.2024 11:00

Цитата:

Сообщение от MrKirill1232

Даже такой "жутко-код" выполнял свои функции.

Я изучу ваш код спасибо!

И 121 как я понимаю по вашему коду берет ключ из имени файла?

MrKirill1232 14.10.2024 11:02

Цитата:

Сообщение от BIT_hack

Я изучу ваш код спасибо!
И 121 как я понимаю по вашему коду берет ключ из имени файла?

да, так и есть.

BIT_hack 14.10.2024 13:17

Цитата:

Сообщение от MrKirill1232

да, так и есть.

Спасибо разобрался в C# нужно было выбрать кодировку

C#:


Код:

Encoding
.
Unicode
.
GetBytes
(
"Lineage2Ver111"
)


kick 20.11.2024 00:46

@BIT_hack,

C#:


Код:

private
const
int
HeaderSize
=
28
;
private
const
byte
XorKey
=
0xAC
;
private
const
string
ExpectedHeader
=
"Lineage2Ver111"
;
private
static
void
DecryptFile
(
string
filePath
)
{
using
var
fileStream
=
new
FileStream
(
filePath
,
FileMode
.
Open
,
FileAccess
.
ReadWrite
)
;
Span

headerBytes
=
stackalloc
byte
[
HeaderSize
]
;
fileStream
.
Read
(
headerBytes
)
;
string
header
=
System
.
Text
.
Encoding
.
Unicode
.
GetString
(
headerBytes
)
;
if
(
!
header
.
StartsWith
(
ExpectedHeader
)
)
{
//Console.WriteLine($"File '{filePath}' does not require decryption."); or display message or just skip
return
;
}
string
tempFilePath
=
$
"{filePath}.tmp"
;
using
var
tempFileStream
=
new
FileStream
(
tempFilePath
,
FileMode
.
Create
,
FileAccess
.
Write
)
;
fileStream
.
Seek
(
HeaderSize
,
SeekOrigin
.
Begin
)
;
var
buffer
=
ArrayPool

.
Shared
.
Rent
(
8192
)
;
int
bytesRead
;
while
(
(
bytesRead
=
fileStream
.
Read
(
buffer
,
0
,
buffer
.
Length
)
)
>
0
)
{
for
(
int
i
=
0
;
i

.
Shared
.
Return
(
buffer
)
;
fileStream
.
Close
(
)
;
tempFileStream
.
Close
(
)
;
File
.
Delete
(
filePath
)
;
File
.
Move
(
tempFilePath
,
filePath
)
;
}


MrKirill1232 20.11.2024 00:58

Цитата:

Сообщение от kick

@BIT_hack,

C#:


Код:

private
const
int
HeaderSize
=
28
;
private
const
byte
XorKey
=
0xAC
;
private
const
string
ExpectedHeader
=
"Lineage2Ver111"
;
private
static
void
DecryptFile
(
string
filePath
)
{
using
var
fileStream
=
new
FileStream
(
filePath
,
FileMode
.
Open
,
FileAccess
.
ReadWrite
)
;
Span

headerBytes
=
stackalloc
byte
[
HeaderSize
]
;
fileStream
.
Read
(
headerBytes
)
;
string
header
=
System
.
Text
.
Encoding
.
Unicode
.
GetString
(
headerBytes
)
;
if
(
!
header
.
StartsWith
(
ExpectedHeader
)
)
{
//Console.WriteLine($"File '{filePath}' does not require decryption."); or display message or just skip
return
;
}
string
tempFilePath
=
$
"{filePath}.tmp"
;
using
var
tempFileStream
=
new
FileStream
(
tempFilePath
,
FileMode
.
Create
,
FileAccess
.
Write
)
;
fileStream
.
Seek
(
HeaderSize
,
SeekOrigin
.
Begin
)
;
var
buffer
=
ArrayPool

.
Shared
.
Rent
(
8192
)
;
int
bytesRead
;
while
(
(
bytesRead
=
fileStream
.
Read
(
buffer
,
0
,
buffer
.
Length
)
)
>
0
)
{
for
(
int
i
=
0
;
i

.
Shared
.
Return
(
buffer
)
;
fileStream
.
Close
(
)
;
tempFileStream
.
Close
(
)
;
File
.
Delete
(
filePath
)
;
File
.
Move
(
tempFilePath
,
filePath
)
;
}


вообще лучше будет декодировать файл по нужде наверное , Ане сразу весь грузить...

111 и 121 поддерживаю чтение определенного фрагмента, а не блоков ранее заложенные размера.

kick 20.11.2024 00:59

Цитата:

Сообщение от MrKirill1232

вообще лучше будет декодировать файл по нужде наверное , Ане сразу весь грузить...
111 и 121 поддерживаю чтение определенного фрагмента, а не блоков ранее заложенные размера.


MrKirill1232 20.11.2024 01:03

Цитата:

Сообщение от kick

хз, я баловался с .utx и .u файлами - причитав заголовок (узнав что за крипт) - после этого просто читал значения в разных местах без полного чтения файла

kick 20.11.2024 01:16

Цитата:

Сообщение от MrKirill1232

хз, я баловался с .utx и .u файлами - причитав заголовок (узнав что за крипт) - после этого просто читал значения в разных местах без полного чтения файла

Ещё раз

Открыли файл

Создали буфер в стеке для считывания заголовка длиной первых 28 байт и потом прочитали эти 28 байт...

Проверили соответствует ли заголовок 111 кодировки или нет, если нет, просто вышли и всё. Закомментирован вывод в командной строке и указано отобразить сообщением или ещё как или просто ничего не выводить, потому что не содержится указание на крипт.

Что ещё надо? Какие оптимизации, для другой и других кодировок можно сделать по другому, это лишь пример быстрой работы с созданием минимальных аллокаций. А делать тоже самое с выделением байтов и определять кодировку файла, какой смысл?

BIT_hack 20.11.2024 08:26

Спасибо ребята я разобрался там оказалось не все так страшно эти файл можно декодировать в несколько строк кода!

Алгоритм такой как вы описали выше!


Время: 20:27