cpp implementation for ArchiveStorageDecryptor.decrypt_block · zzy-hacker/UnityPy@ec74e4b · GitHub
Skip to content

Commit ec74e4b

Browse files
AXiX-officialK0lb3
authored andcommitted
cpp implementation for ArchiveStorageDecryptor.decrypt_block
1 parent fe7db50 commit ec74e4b

5 files changed

Lines changed: 117 additions & 1 deletion

File tree

‎UnityPy/UnityPyBoost.pyi‎

Lines changed: 7 additions & 0 deletions

‎UnityPy/helpers/ArchiveStorageManager.py‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@
44

55
from ..streams import EndianBinaryReader
66

7+
try:
8+
from UnityPy import UnityPyBoost
9+
except ImportError:
10+
UnityPyBoost = None
11+
712
UNITY3D_SIGNATURE = b"#$unity3dchina!@"
813
DECRYPT_KEY: bytes = None
914

@@ -101,6 +106,11 @@ def __init__(self, reader: EndianBinaryReader) -> None:
101106
)
102107

103108
def decrypt_block(self, data: bytes, index: int):
109+
110+
if UnityPyBoost:
111+
UnityPyBoost.decrypt_block(bytes(self.index), bytes(self.substitute), data, index)
112+
return data
113+
104114
offset = 0
105115
size = len(data)
106116
data = bytearray(data)
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
// based on https://github.com/RazTools/Studio/blob/main/AssetStudio/Crypto/UnityCN.cs
2+
3+
#include "ArchiveStorageDecryptor.hpp"
4+
#include <Python.h>
5+
6+
inline unsigned char decrypt_byte(unsigned char* bytes, uint64_t& offset, uint64_t& index, unsigned char* index_data, unsigned char* substitute_data)
7+
{
8+
unsigned char count_byte = substitute_data[((index >> 2) & 3) + 4]
9+
+ substitute_data[index & 3]
10+
+ substitute_data[((index >> 4) & 3) + 8]
11+
+ substitute_data[((unsigned char)index >> 6) + 12];
12+
bytes[offset] = (unsigned char)((index_data[bytes[offset] & 0xF] - count_byte) & 0xF | 0x10 * (index_data[bytes[offset] >> 4] - count_byte));
13+
count_byte = bytes[offset++];
14+
index++;
15+
return count_byte;
16+
}
17+
18+
inline uint64_t decrypt(unsigned char* bytes, uint64_t index, uint64_t remaining, unsigned char* index_data, unsigned char* substitute_data)
19+
{
20+
uint64_t offset = 0;
21+
22+
unsigned char current_byte = decrypt_byte(bytes, offset, index, index_data, substitute_data);
23+
uint64_t current_byte_high = current_byte >> 4;
24+
uint64_t current_byte_low = current_byte & 0xF;
25+
26+
if (current_byte_high == 0xF)
27+
{
28+
unsigned char count_byte;
29+
do
30+
{
31+
count_byte = decrypt_byte(bytes, offset, index, index_data, substitute_data);
32+
current_byte_high += count_byte;
33+
} while (count_byte == 0xFF);
34+
}
35+
36+
offset += current_byte_high;
37+
38+
if (offset < remaining)
39+
{
40+
decrypt_byte(bytes, offset, index, index_data, substitute_data);
41+
decrypt_byte(bytes, offset, index, index_data, substitute_data);
42+
if (current_byte_low == 0xF)
43+
{
44+
unsigned char count_byte;
45+
do
46+
{
47+
count_byte = decrypt_byte(bytes, offset, index, index_data, substitute_data);
48+
} while (count_byte == 0xFF);
49+
}
50+
}
51+
52+
return offset;
53+
}
54+
55+
PyObject* decrypt_block(PyObject* self, PyObject* args) {
56+
PyObject* py_index_bytes;
57+
PyObject* py_substitute_bytes;
58+
PyObject* py_data;
59+
uint64_t index;
60+
61+
if (!PyArg_ParseTuple(args, "OOOi", &py_index_bytes, &py_substitute_bytes, &py_data, &index)) {
62+
return NULL;
63+
}
64+
65+
Py_buffer view;
66+
if (PyObject_GetBuffer(py_data, &view, PyBUF_SIMPLE) != 0) {
67+
return NULL;
68+
}
69+
70+
if (!PyBytes_Check(py_index_bytes) || !PyBytes_Check(py_substitute_bytes)) {
71+
PyBuffer_Release(&view);
72+
PyErr_SetString(PyExc_TypeError, "Attributes 'index' and 'substitute' must be bytes");
73+
return NULL;
74+
}
75+
76+
unsigned char* data = (unsigned char*)view.buf;
77+
uint64_t size = (uint64_t)view.len;
78+
unsigned char* index_data = (unsigned char*)PyBytes_AS_STRING(py_index_bytes);
79+
unsigned char* substitute_data = (unsigned char*)PyBytes_AS_STRING(py_substitute_bytes);
80+
81+
uint64_t offset = 0;
82+
while (offset < size) {
83+
offset += decrypt(data + offset, index++, size - offset, index_data, substitute_data);
84+
}
85+
86+
PyBuffer_Release(&view);
87+
Py_RETURN_NONE;
88+
}
89+
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#define PY_SSIZE_T_CLEAN
2+
#pragma once
3+
#include <Python.h>
4+
5+
PyObject* decrypt_block(PyObject* self, PyObject* args);

‎UnityPyBoost/UnityPyBoost.cpp‎

Lines changed: 6 additions & 1 deletion

0 commit comments

Comments
 (0)