wip: header parsing

This commit is contained in:
2025-02-27 16:10:30 +08:00
parent 79e22e193a
commit 2cab8c4c92
5 changed files with 80 additions and 2 deletions

View File

@@ -37,7 +37,7 @@ def decrypt_process(runtimes: dict[str, RuntimeInfo], sequences: list[tuple[str,
with open(dest_path + '.1shot.seq', 'wb') as f: with open(dest_path + '.1shot.seq', 'wb') as f:
f.write(b'\xa1' + runtime.runtime_aes_key) f.write(b'\xa1' + runtime.runtime_aes_key)
f.write(b'\xa2' + runtime.mix_str_aes_nonce()) f.write(b'\xa2' + runtime.mix_str_aes_nonce())
f.write(b'\xf0\xf0') f.write(b'\xf0\xff')
f.write(data[:cipher_text_offset]) f.write(data[:cipher_text_offset])
f.write(general_aes_ctr_decrypt( f.write(general_aes_ctr_decrypt(
data[cipher_text_offset:cipher_text_offset+cipher_text_length], runtime.runtime_aes_key, nonce)) data[cipher_text_offset:cipher_text_offset+cipher_text_length], runtime.runtime_aes_key, nonce))

View File

@@ -35,6 +35,9 @@ public:
CO_FUTURE_GENERATOR_STOP = 0x800000, // 3.5 -> CO_FUTURE_GENERATOR_STOP = 0x800000, // 3.5 ->
CO_FUTURE_ANNOTATIONS = 0x1000000, // 3.7 -> CO_FUTURE_ANNOTATIONS = 0x1000000, // 3.7 ->
CO_NO_MONITORING_EVENTS = 0x2000000, // 3.13 -> CO_NO_MONITORING_EVENTS = 0x2000000, // 3.13 ->
// TODO: Shift things
CO_PYARMOR_OBFUSCATED = 0x20000000,
}; };
PycCode(int type = TYPE_CODE) PycCode(int type = TYPE_CODE)

View File

@@ -251,6 +251,75 @@ void PycModule::loadFromMarshalledFile(const char* filename, int major, int mino
m_code = LoadObject(&in, this).cast<PycCode>(); m_code = LoadObject(&in, this).cast<PycCode>();
} }
void PycModule::loadFromOneshotSequenceFile(const char *filename)
{
PycFile in(filename);
if (!in.isOpen())
{
fprintf(stderr, "Error opening file %s\n", filename);
return;
}
bool oneshot_seq_header = true;
while (oneshot_seq_header)
{
int indicator = in.getByte();
switch (indicator)
{
case 0xA1:
in.getBuffer(16, this->pyarmor_aes_key);
break;
case 0xA2:
in.getBuffer(12, this->pyarmor_mix_str_aes_nonce);
break;
case 0xF0:
break;
case 0xFF:
oneshot_seq_header = false;
break;
default:
fprintf(stderr, "Unknown 1-shot sequence indicator %02X\n", indicator);
break;
}
}
// Write only. Some fields unknown to us or not needed for decryption are discarded.
char discard_buffer[64];
char pyarmor_header[64];
in.getBuffer(64, pyarmor_header);
this->m_maj = pyarmor_header[9];
this->m_min = pyarmor_header[10];
this->m_unicode = (m_maj >= 3);
unsigned int remain_header_length = *(unsigned int *)(pyarmor_header + 28) - 64;
while (remain_header_length)
{
unsigned int discard_length = (remain_header_length > 64) ? 64 : remain_header_length;
in.getBuffer(discard_length, discard_buffer);
remain_header_length -= discard_length;
}
// For 1-shot sequence, the following part has been decrypted once.
unsigned int code_object_offset = in.get32();
unsigned int co_code_aes_nonce_xor_key_procedure_length = in.get32();
this->pyarmor_co_code_aes_nonce_xor_enabled = (co_code_aes_nonce_xor_key_procedure_length > 0);
unsigned int remain_second_part_length = code_object_offset - 8;
while (remain_second_part_length)
{
unsigned int discard_length = (remain_second_part_length > 64) ? 64 : remain_second_part_length;
in.getBuffer(discard_length, discard_buffer);
remain_second_part_length -= discard_length;
}
if (this->pyarmor_co_code_aes_nonce_xor_enabled)
{
// TODO: Implement the decryption procedure.
}
m_code = LoadObject(&in, this).cast<PycCode>();
}
PycRef<PycString> PycModule::getIntern(int ref) const PycRef<PycString> PycModule::getIntern(int ref) const
{ {
if (ref < 0 || (size_t)ref >= m_interns.size()) if (ref < 0 || (size_t)ref >= m_interns.size())

View File

@@ -46,6 +46,7 @@ public:
void loadFromFile(const char* filename); void loadFromFile(const char* filename);
void loadFromMarshalledFile(const char *filename, int major, int minor); void loadFromMarshalledFile(const char *filename, int major, int minor);
void loadFromOneshotSequenceFile(const char* filename);
bool isValid() const { return (m_maj >= 0) && (m_min >= 0); } bool isValid() const { return (m_maj >= 0) && (m_min >= 0); }
int majorVer() const { return m_maj; } int majorVer() const { return m_maj; }
@@ -87,6 +88,11 @@ private:
int m_maj, m_min; int m_maj, m_min;
bool m_unicode; bool m_unicode;
char pyarmor_aes_key[16];
char pyarmor_mix_str_aes_nonce[12];
bool pyarmor_co_code_aes_nonce_xor_enabled;
char pyarmor_co_code_aes_nonce_xor_key[12];
PycRef<PycCode> m_code; PycRef<PycCode> m_code;
std::vector<PycRef<PycString>> m_interns; std::vector<PycRef<PycString>> m_interns;
std::vector<PycRef<PycObject>> m_refs; std::vector<PycRef<PycObject>> m_refs;

View File

@@ -23,7 +23,7 @@ static const char* flag_names[] = {
"CO_FUTURE_PRINT_FUNCTION", "CO_FUTURE_UNICODE_LITERALS", "CO_FUTURE_BARRY_AS_BDFL", "CO_FUTURE_PRINT_FUNCTION", "CO_FUTURE_UNICODE_LITERALS", "CO_FUTURE_BARRY_AS_BDFL",
"CO_FUTURE_GENERATOR_STOP", "CO_FUTURE_GENERATOR_STOP",
"CO_FUTURE_ANNOTATIONS", "CO_NO_MONITORING_EVENTS", "<0x4000000>", "<0x8000000>", "CO_FUTURE_ANNOTATIONS", "CO_NO_MONITORING_EVENTS", "<0x4000000>", "<0x8000000>",
"<0x10000000>", "<0x20000000>", "<0x40000000>", "<0x80000000>" "<0x10000000>", "CO_PYARMOR_OBFUSCATED", "<0x40000000>", "<0x80000000>"
}; };
static void print_coflags(unsigned long flags, std::ostream& pyc_output) static void print_coflags(unsigned long flags, std::ostream& pyc_output)