Skip to content

Instantly share code, notes, and snippets.

@tatarize
Created July 23, 2019 22:14
Show Gist options
  • Save tatarize/4abd5345eb269603cfc98ff4070717d8 to your computer and use it in GitHub Desktop.
Save tatarize/4abd5345eb269603cfc98ff4070717d8 to your computer and use it in GitHub Desktop.
Archive Lib Expand Deobfuscated Source
#include <iostream>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <fstream>
#include "show_dump2.h"
using namespace std;
void expand(unsigned char *input, unsigned char *output, int compressedSize, int bits_for_buffer);
/*****************************************
* HUS Expand Variables
****************************************/
unsigned char *sliding_window;
short remaining_bit_length;
short sliding_window_size;
short window_mask;
unsigned char *bitlengths_511;
unsigned char *bitlengths_19;
unsigned short bitstream_window;
unsigned short *g1021_bit0_token_lookup;
unsigned short *g1021_bit1_token_lookup;
unsigned short *g12bit_token_lookup;
unsigned short *g8bit_token_lookup;
short end_of_file_or_error;
unsigned short elements_before_reset;
unsigned char remaining_bits;
short bytes_left_in_chunk;
int mStatus;
int currentIndex;
long remainingBytes;
unsigned char *outputArray;
unsigned char *inputArray;
unsigned char *inputBuffer;
int currentPosition;
int outputPosition;
/*****************************************
* HUS Expand Functions
****************************************/
void update_tables(int lengths_table_size, const unsigned char *lengths_table, int bit_depth,
unsigned short *token_tables, unsigned short token_table_size);
void bitstream_initialize();
void bitstream_forward(int bits_forward);
unsigned short get_bits(int bit_count);
int decompress_main();
unsigned short reset_check_read_token_12_4();
unsigned short read_token_12_4();
unsigned short read_token_8_8();
void setup_8_bit_table(short clear_amount, short pos_at_skip_2bit_length);
void setup_12_bit_table();
void expand(unsigned char *input, unsigned char *output, int compressedSize, int bits_for_buffer) {
currentPosition = 0;
outputPosition = 0;
currentIndex = 0;
mStatus = 0;
outputArray = output;
inputArray = input;
remainingBytes = compressedSize;
if (bits_for_buffer > 14 || bits_for_buffer < 10) {
mStatus = -1;
sliding_window_size = 2;
} else {
sliding_window_size = (short) (1U << bits_for_buffer); //[10-14] 1024-16384
}
remaining_bit_length = 0;
end_of_file_or_error = 0;
bytes_left_in_chunk = 0;
elements_before_reset = 0;
remaining_bits = 0;
window_mask = (short) (sliding_window_size - 1);
sliding_window = (unsigned char *) malloc(sizeof(unsigned char) * (sliding_window_size + 2));
if (sliding_window) memset(sliding_window, 0, (sliding_window_size + 2) * sizeof(unsigned char));
g12bit_token_lookup = (unsigned short *) malloc(sizeof(unsigned short) * 4096);
if (g12bit_token_lookup) memset(g12bit_token_lookup, 0, 4096 * sizeof(unsigned short));
g8bit_token_lookup = (unsigned short *) malloc(sizeof(unsigned short) * 256);
if (g8bit_token_lookup) memset(g8bit_token_lookup, 0, 256 * sizeof(unsigned short));
g1021_bit0_token_lookup = (unsigned short *) malloc(sizeof(unsigned short) * 1021);
if (g1021_bit0_token_lookup) memset(g1021_bit0_token_lookup, 0, 1021 * sizeof(unsigned short));
g1021_bit1_token_lookup = (unsigned short *) malloc(sizeof(unsigned short) * 1021);
if (g1021_bit1_token_lookup) memset(g1021_bit1_token_lookup, 0, 1021 * sizeof(unsigned short));
bitlengths_511 = (unsigned char *) malloc(sizeof(unsigned char) * 511);
if (bitlengths_511) memset(bitlengths_511, 0, 511 * sizeof(unsigned char));
bitlengths_19 = (unsigned char *) malloc(sizeof(unsigned char) * 19);
if (bitlengths_19) memset(bitlengths_19, 0, 19 * sizeof(unsigned char));
if (sliding_window == nullptr ||
g1021_bit0_token_lookup == nullptr ||
g1021_bit1_token_lookup == nullptr ||
bitlengths_511 == nullptr ||
bitlengths_19 == nullptr ||
g12bit_token_lookup == nullptr ||
g8bit_token_lookup == nullptr ||
inputBuffer == nullptr) {
mStatus = -1;
}
decompress_main();
free(sliding_window);
free(g1021_bit0_token_lookup);
free(g1021_bit1_token_lookup);
free(bitlengths_511);
free(bitlengths_19);
free(g12bit_token_lookup);
free(g8bit_token_lookup);
}
void bitstream_initialize() {
elements_before_reset = 0;
bitstream_window = 0;
remaining_bits = 0;
remaining_bit_length = 0;
bytes_left_in_chunk = 0;
bitstream_forward(16);
}
unsigned short get_bits(int bit_count) {
auto bits_off_scope = bitstream_window >> (16 - bit_count);
bitstream_forward(bit_count);
return bits_off_scope;
}
void bitstream_forward(int bits_forward) {
while (bits_forward > remaining_bit_length) {
bits_forward -= remaining_bit_length;
bitstream_window = (bitstream_window << remaining_bit_length) + (remaining_bits >> (8 - remaining_bit_length));
if (bytes_left_in_chunk <= 0) { //new block needed
currentIndex = 0;
if (remainingBytes >= 0 && remainingBytes < 512) { //incomplete block
inputBuffer = &inputArray[currentPosition];
currentPosition += remainingBytes;
bytes_left_in_chunk = (short) remainingBytes;
remainingBytes -= bytes_left_in_chunk;
} else { //full block.
inputBuffer = &inputArray[currentPosition];
currentPosition += 512;
bytes_left_in_chunk = 512;
}
if (bytes_left_in_chunk <= 0) end_of_file_or_error++;
}
remaining_bits = inputBuffer[currentIndex++];
bytes_left_in_chunk--;
remaining_bit_length = 8;
}
remaining_bit_length = (short) (remaining_bit_length - bits_forward);
bitstream_window = (bitstream_window << bits_forward) + (remaining_bits >> (8 - bits_forward));
remaining_bits <<= bits_forward;
}
int decompress_main() {
short current_pos = 0;
end_of_file_or_error = 0;
bitstream_initialize();
while (end_of_file_or_error < 5) {
short token;
token = (short) reset_check_read_token_12_4();
if (token <= 255) {
//this is simply a value.
sliding_window[current_pos] = (unsigned char) token;
if (++current_pos >= sliding_window_size) {
current_pos = 0;
memcpy(&outputArray[outputPosition], sliding_window, static_cast<size_t>(sliding_window_size));
outputPosition += sliding_window_size;
}
} else {
//this is a lookup. 256 <= token <= 511
auto length_move = (short) (token - 253);
if (length_move == 257) break;
auto relative_lookback = (current_pos - read_token_8_8() - 1);
auto read_pos = (short) (relative_lookback & window_mask);
if (read_pos < sliding_window_size - 257 && current_pos < sliding_window_size - 257) {
while (--length_move >= 0) {
sliding_window[current_pos++] = sliding_window[read_pos++];
}
} else {
while (--length_move >= 0) {
sliding_window[current_pos] = sliding_window[read_pos];
if (++current_pos >= sliding_window_size) {
current_pos = 0;
memcpy(&outputArray[outputPosition], sliding_window, static_cast<size_t>(sliding_window_size));
outputPosition += sliding_window_size;
}
read_pos = (short) ((read_pos + 1) & window_mask);
}
}
}
}
if (current_pos != 0) {
memcpy(&outputArray[outputPosition], sliding_window, static_cast<size_t>(current_pos));
outputPosition += current_pos;
}
return 0;
}
unsigned short reset_check_read_token_12_4() {
if (elements_before_reset == 0) { //initialized or reset
elements_before_reset = get_bits(16);
setup_8_bit_table(19, 3);
setup_12_bit_table();
setup_8_bit_table(15, -1);
if (mStatus < 0) return 0;
}
elements_before_reset--;
return read_token_12_4();
}
unsigned short read_token_12_4() {
auto index_value = bitstream_window >> 4U;
auto token = g12bit_token_lookup[index_value];
if (token >= 511) { //is outside bitlength lookup
unsigned short bit_mask_3 = 1U << 3U;
do {
if (bitstream_window & bit_mask_3) {
token = g1021_bit1_token_lookup[token];
} else {
token = g1021_bit0_token_lookup[token];
}
bit_mask_3 >>= 1U;
} while (token >= 511);
}
auto token_length = bitlengths_511[token];
bitstream_forward(token_length);
return token;
}
unsigned short read_token_8_8() {
auto index_value = bitstream_window >> 8U;
auto token = g8bit_token_lookup[index_value];
if (token >= 15) {
unsigned short bit_mask_7 = 1U << 7U;
do {
if (bitstream_window & bit_mask_7) {
token = g1021_bit1_token_lookup[token];
} else {
token = g1021_bit0_token_lookup[token];
}
bit_mask_7 >>= 1U;
} while (token >= 15);
}
auto a = bitlengths_19[token];
bitstream_forward(a);
if (token != 0) {
token--;
token = (1U << token) + get_bits(token);
}
return token;
}
void setup_8_bit_table(short clear_amount, short pos_at_skip_2bit_length) {
short get_header = get_bits(5);
if (get_header == 0) { //0b00000 means 19chars blank and set all g256 to next_five_bits
auto next_5_bits = get_bits(5);
for (int i = 0; i < clear_amount; i++) bitlengths_19[i] = 0;
for (int i = 0; i < 256; i++) g8bit_token_lookup[i] = next_5_bits;
} else {
int i = 0;
while (i < get_header) {
auto value = (short) (bitstream_window >> 13U); //lookahead 3 bits.
if (value == 7) { //0b111
unsigned short mask_bit_12 = 1U << 12U;
while (mask_bit_12 & bitstream_window) { //find next 0 in bitstream.
mask_bit_12 >>= 1U;
value++;
}
} //lookahead either 1-6 001 - 110, or 1110 = 7, 11110=8, 111110=9 up to 11111111_11111111 = 20
bitstream_forward((value < 7) ? 3 : value - 3); //remove value out
bitlengths_19[i++] = (unsigned char) value;
if (i == pos_at_skip_2bit_length) {
short length_to_zero = get_bits(2);
while (--length_to_zero >= 0) bitlengths_19[i++] = 0;
}
}
while (i < clear_amount) bitlengths_19[i++] = 0;
update_tables(clear_amount, bitlengths_19, 8, g8bit_token_lookup, 256);
}
}
void setup_12_bit_table() {
auto get_header = get_bits(9);
if (get_header == 0) {
auto set_value = get_bits(9);
for (short i = 0; i < 511; i++) bitlengths_511[i] = 0;
for (short j = 0; j < 4096; j++) g12bit_token_lookup[j] = set_value;
} else {
short i = 0;
while (i < get_header) {
auto upper_byte = bitstream_window >> 8;
short token = g8bit_token_lookup[upper_byte]; //MUST BE SIGNED.
if (token >= 19) {
unsigned short bit_mask_7 = 1U << 7U;
do {
if ((bitstream_window & bit_mask_7) != 0) {
token = (short) g1021_bit1_token_lookup[token];
} else {
token = (short) g1021_bit0_token_lookup[token];
}
bit_mask_7 >>= 1;
} while (token >= 19);
}
auto m = bitlengths_19[token];
bitstream_forward(m);
if (token <= 2) {
if (token == 0) {
token = 1;
} else if (token == 1) {
token = (short) (get_bits(4) + 3);
} else {
token = (short) (get_bits(9) + 20);
}
while (--token >= 0) {
bitlengths_511[i++] = 0;
}
} else {
bitlengths_511[i++] = (unsigned char) (token - 2);
}
}
while (i < 511) {
bitlengths_511[i++] = 0; //everything left set to zero.
}
update_tables(511, bitlengths_511, 12, g12bit_token_lookup, 4096);
}
}
void update_tables(int lengths_table_size, const unsigned char *lengths_table, int bit_depth,
unsigned short *token_tables, unsigned short token_table_size) {
unsigned short length_sums[17], step_2[18], step_3[17];
for (int i = 0; i <= 16; i++) {
length_sums[i] = 0;
}
for (int i = 0; i < lengths_table_size; i++) {
auto index = lengths_table[i];
length_sums[index]++;
}
step_2[0] = 0;
step_2[1] = 0;
for (int i = 1; i <= 16; i++) {
step_2[i + 1] = step_2[i] + (length_sums[i] << (16 - i));
}
if (step_2[17] != 0) {
mStatus = -1;
end_of_file_or_error = 10; //error, abort?
return;
}
auto remain_bits = 16 - bit_depth;
step_3[0] = 0;
int q;
for (q = 1; q <= bit_depth; q++) {
step_2[q] >>= remain_bits;
step_3[q] = (unsigned short) (1U << (bit_depth - q));
}
for (; q <= 16; q++) {
step_3[q] = (unsigned short) (1U << (16 - q));
}
int r = step_2[bit_depth + 1] >> remain_bits;
if (r != 0) {
unsigned int max_value_for_bitdepth = 1U << bit_depth;
while (r != max_value_for_bitdepth) token_tables[r++] = 0;
}
int a = lengths_table_size;
unsigned int bit_mask_msd = 1U << (15 - bit_depth);
for (int c_index = 0; c_index < lengths_table_size; c_index++) {
int c_value = lengths_table[c_index];
if (c_value == 0) continue;
int sum_of_steps_2_3 = step_2[c_value] + step_3[c_value];
if (c_value <= bit_depth) {
if (sum_of_steps_2_3 > token_table_size) {
mStatus = -1;
end_of_file_or_error = 10;
//error abort.
return;
}
for (int i = step_2[c_value]; i < sum_of_steps_2_3; i++) {
token_tables[i] = (unsigned short) c_index;
}
} else {
unsigned int step_2_c_value = step_2[c_value];
unsigned short *table_element = &token_tables[step_2_c_value >> remain_bits];
int i = c_value - bit_depth;
while (i != 0) {
if (*table_element == 0) {
g1021_bit1_token_lookup[a] = g1021_bit0_token_lookup[a] = 0;
*table_element = (unsigned short) a++;
}
if (step_2_c_value & bit_mask_msd) {
table_element = &g1021_bit1_token_lookup[*table_element];
} else {
table_element = &g1021_bit0_token_lookup[*table_element];
}
step_2_c_value <<= 1;
i--;
}
*table_element = (unsigned short) c_index;
}
step_2[c_value] = (unsigned short) sum_of_steps_2_3;
}
}
int main() {
char *memblock;
cout << "Hus parser." << endl;
ifstream infile;
//infile.open("C:\\Users\\Tat\\CLionProjects\\deobf-expand\\BN00883_A.HUS", ios::in|ios::binary|ios::ate);
infile.open(R"(C:\Users\Tat\CLionProjects\deobf-expand\wet.hus)", ios::in | ios::binary | ios::ate);
unsigned char *input = nullptr;
if (infile.is_open()) {
infile.seekg(0, ios::end);
int length_of_file = static_cast<int>(infile.tellg());
infile.seekg(0, ios::beg);
char *read = new char[4];
infile.read(read, 4);
int magic = ((read[3] & 0xFF) << 24) | ((read[2] & 0xFF) << 16) | ((read[1] & 0xFF) << 8) | (read[0] & 0xFF);
cout << magic << endl;
infile.read(read, 4);
int stitch_count =
((read[3] & 0xFF) << 24) | ((read[2] & 0xFF) << 16) | ((read[1] & 0xFF) << 8) | (read[0] & 0xFF);
cout << stitch_count << endl;
infile.read(read, 4);
int color_count =
((read[3] & 0xFF) << 24) | ((read[2] & 0xFF) << 16) | ((read[1] & 0xFF) << 8) | (read[0] & 0xFF);
cout << color_count << endl;
infile.read(read, 4);
infile.read(read, 4);
infile.read(read, 4);
int command_offset =
((read[3] & 0xFF) << 24) | ((read[2] & 0xFF) << 16) | ((read[1] & 0xFF) << 8) | (read[0] & 0xFF);
cout << command_offset << endl;
infile.read(read, 4);
int x_offset = ((read[3] & 0xFF) << 24) | ((read[2] & 0xFF) << 16) | ((read[1] & 0xFF) << 8) | (read[0] & 0xFF);
cout << x_offset << endl;
infile.read(read, 4);
int y_offset = ((read[3] & 0xFF) << 24) | ((read[2] & 0xFF) << 16) | ((read[1] & 0xFF) << 8) | (read[0] & 0xFF);
cout << y_offset << endl;
int type = 10;
int len_compressed;
int len_uncompressed;
unsigned char *decompressedData;
infile.seekg(0, ios::beg);
infile.seekg(command_offset);
len_compressed = x_offset - command_offset;
memblock = new char[len_compressed];
infile.read(memblock, len_compressed);
input = reinterpret_cast<unsigned char *>(memblock);
len_uncompressed = stitch_count + 1;
decompressedData = (unsigned char *) malloc(sizeof(unsigned char) * len_uncompressed);
expand(input, decompressedData, len_uncompressed, type);
show_dump(5, decompressedData, static_cast<unsigned int>(len_uncompressed), stdout);
cout << endl << endl << endl << endl;
infile.seekg(0, ios::beg);
infile.seekg(x_offset);
len_compressed = y_offset - x_offset;
memblock = new char[len_compressed];
infile.read(memblock, len_compressed);
input = reinterpret_cast<unsigned char *>(memblock);
len_uncompressed = stitch_count;
decompressedData = (unsigned char *) malloc(sizeof(unsigned char) * len_uncompressed);
expand(input, decompressedData, len_uncompressed, type);
show_dump(5, decompressedData, static_cast<unsigned int>(len_uncompressed), stdout);
cout << endl << endl << endl << endl;
infile.seekg(0, ios::beg);
infile.seekg(y_offset);
len_compressed = length_of_file - y_offset;
memblock = new char[len_compressed];
infile.read(memblock, len_compressed);
input = reinterpret_cast<unsigned char *>(memblock);
len_uncompressed = stitch_count;
decompressedData = (unsigned char *) malloc(sizeof(unsigned char) * len_uncompressed);
expand(input, decompressedData, len_uncompressed, type);
show_dump(5, decompressedData, static_cast<unsigned int>(len_uncompressed), stdout);
infile.close();
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment