feat: mix str for disasm
This commit is contained in:
@@ -116,7 +116,7 @@ int Pyc::ByteToOpcode(int maj, int min, int opcode)
|
||||
}
|
||||
|
||||
void print_const(std::ostream& pyc_output, PycRef<PycObject> obj, PycModule* mod,
|
||||
const char* parent_f_string_quote)
|
||||
const char* parent_f_string_quote, bool das_decrypt_print)
|
||||
{
|
||||
if (obj == NULL) {
|
||||
pyc_output << "<NULL>";
|
||||
@@ -131,7 +131,9 @@ void print_const(std::ostream& pyc_output, PycRef<PycObject> obj, PycModule* mod
|
||||
case PycObject::TYPE_ASCII_INTERNED:
|
||||
case PycObject::TYPE_SHORT_ASCII:
|
||||
case PycObject::TYPE_SHORT_ASCII_INTERNED:
|
||||
obj.cast<PycString>()->print(pyc_output, mod, false, parent_f_string_quote);
|
||||
das_decrypt_print
|
||||
? obj.cast<PycString>()->dasPrintAndDecrypt(pyc_output, mod, false, parent_f_string_quote)
|
||||
: obj.cast<PycString>()->print(pyc_output, mod, false, parent_f_string_quote);
|
||||
break;
|
||||
case PycObject::TYPE_TUPLE:
|
||||
case PycObject::TYPE_SMALL_TUPLE:
|
||||
@@ -362,7 +364,7 @@ void bc_disasm(std::ostream& pyc_output, PycRef<PycCode> code, PycModule* mod,
|
||||
try {
|
||||
auto constParam = code->getConst(operand);
|
||||
formatted_print(pyc_output, "%d: ", operand);
|
||||
print_const(pyc_output, constParam, mod);
|
||||
print_const(pyc_output, constParam, mod, nullptr, true);
|
||||
} catch (const std::out_of_range &) {
|
||||
formatted_print(pyc_output, "%d <INVALID>", operand);
|
||||
}
|
||||
|
@@ -28,7 +28,7 @@ int ByteToOpcode(int maj, int min, int opcode);
|
||||
}
|
||||
|
||||
void print_const(std::ostream& pyc_output, PycRef<PycObject> obj, PycModule* mod,
|
||||
const char* parent_f_string_quote = nullptr);
|
||||
const char* parent_f_string_quote = nullptr, bool das_decrypt_print = false);
|
||||
void bc_next(PycBuffer& source, PycModule* mod, int& opcode, int& operand, int& pos);
|
||||
void bc_disasm(std::ostream& pyc_output, PycRef<PycCode> code, PycModule* mod,
|
||||
int indent, unsigned flags);
|
||||
|
@@ -15,8 +15,9 @@ def general_aes_ctr_decrypt(data: bytes, key: bytes, nonce: bytes) -> bytes:
|
||||
return cipher.decrypt(data)
|
||||
|
||||
|
||||
def decrypt_process(runtimes: dict[str, RuntimeInfo], sequences: list[tuple[str, bytes]], output_dir: str = None):
|
||||
def decrypt_process(runtimes: dict[str, RuntimeInfo], sequences: list[tuple[str, bytes]], args):
|
||||
logger = logging.getLogger('shot')
|
||||
output_dir: str = args.output_dir or args.directory
|
||||
for path, data in sequences:
|
||||
try:
|
||||
serial_number = data[2:8].decode('utf-8')
|
||||
@@ -28,8 +29,9 @@ def decrypt_process(runtimes: dict[str, RuntimeInfo], sequences: list[tuple[str,
|
||||
if not os.path.exists(dest_dir):
|
||||
os.makedirs(dest_dir)
|
||||
|
||||
with open(dest_path + '.1shot.raw', 'wb') as f:
|
||||
f.write(data)
|
||||
if args.export_raw_data:
|
||||
with open(dest_path + '.1shot.raw', 'wb') as f:
|
||||
f.write(data)
|
||||
|
||||
cipher_text_offset = int.from_bytes(data[28:32], 'little')
|
||||
cipher_text_length = int.from_bytes(data[32:36], 'little')
|
||||
@@ -63,7 +65,7 @@ def decrypt_process(runtimes: dict[str, RuntimeInfo], sequences: list[tuple[str,
|
||||
for line in stderr:
|
||||
if line.startswith('Warning'):
|
||||
logger.warning(f'STDERR {line} ({path})')
|
||||
else:
|
||||
elif not line.startswith('Unsupported opcode:') or args.show_err_opcode:
|
||||
logger.error(f'STDERR {line} ({path})')
|
||||
except Exception as e:
|
||||
logger.error(f'Decrypt failed: {e} ({path})')
|
||||
@@ -90,6 +92,16 @@ def parse_args():
|
||||
help='save output files in another directory instead of in-place, with folder structure remain unchanged',
|
||||
type=str,
|
||||
)
|
||||
parser.add_argument(
|
||||
'--export-raw-data',
|
||||
help='save data found in source files as-is',
|
||||
action='store_true',
|
||||
)
|
||||
parser.add_argument(
|
||||
'--show-err-opcode',
|
||||
help='show pycdc unsupported opcode error',
|
||||
action='store_true',
|
||||
)
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
@@ -145,8 +157,7 @@ def main():
|
||||
if not handled \
|
||||
and specified_runtime is None \
|
||||
and file_name.startswith('pyarmor_runtime') \
|
||||
and not file_name.endswith(('.lnk', '.i64', '.idb', '.id0', '.id1',
|
||||
'.id2', '.nam', '.til', '.bak')):
|
||||
and file_name.endswith(('.pyd', '.so', '.dylib')):
|
||||
try:
|
||||
new_runtime = RuntimeInfo(file_path)
|
||||
runtimes[new_runtime.serial_number] = new_runtime
|
||||
@@ -189,7 +200,7 @@ def main():
|
||||
# TODO: is pyc or single marshalled binary?
|
||||
|
||||
# print(runtimes, [(i[0], i[1][:16]) for i in sequences], args.output_dir or args.directory)
|
||||
decrypt_process(runtimes, sequences, args.output_dir or args.directory)
|
||||
decrypt_process(runtimes, sequences, args)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
@@ -2,6 +2,7 @@
|
||||
#include "pyc_module.h"
|
||||
#include "data.h"
|
||||
#include <stdexcept>
|
||||
#include "plusaes.hpp"
|
||||
|
||||
static bool check_ascii(const std::string& data)
|
||||
{
|
||||
@@ -154,3 +155,28 @@ void PycString::print(std::ostream &pyc_output, PycModule* mod, bool triple,
|
||||
pyc_output << (useQuotes ? '"' : '\'');
|
||||
}
|
||||
}
|
||||
|
||||
void PycString::dasPrintAndDecrypt(std::ostream &stream, PycModule *mod, bool triple, const char *parent_f_string_quote)
|
||||
{
|
||||
if (m_value.empty() || !(m_value[0] & 0x80)
|
||||
|| (m_value[0] & 0x7F) == 0 || (m_value[0] & 0x7F) > 4)
|
||||
return print(stream, mod, triple, parent_f_string_quote);
|
||||
|
||||
std::string result(m_value.substr(1));
|
||||
unsigned char nonce[16] = {0};
|
||||
memcpy(nonce, mod->pyarmor_mix_str_aes_nonce, 12);
|
||||
nonce[15] = 2;
|
||||
|
||||
plusaes::crypt_ctr(
|
||||
(unsigned char *)&result[0],
|
||||
result.length(),
|
||||
mod->pyarmor_aes_key,
|
||||
16,
|
||||
&nonce);
|
||||
|
||||
PycString decrypted(TYPE_UNICODE);
|
||||
decrypted.setValue(result);
|
||||
decrypted.print(stream, mod, triple, parent_f_string_quote);
|
||||
stream << " # ";
|
||||
print(stream, mod, triple, parent_f_string_quote);
|
||||
}
|
||||
|
@@ -30,6 +30,10 @@ public:
|
||||
void print(std::ostream& stream, class PycModule* mod, bool triple = false,
|
||||
const char* parent_f_string_quote = nullptr);
|
||||
|
||||
void dasPrintAndDecrypt(std::ostream& stream, class PycModule* mod,
|
||||
bool triple = false,
|
||||
const char* parent_f_string_quote = nullptr);
|
||||
|
||||
private:
|
||||
std::string m_value;
|
||||
};
|
||||
|
@@ -165,7 +165,7 @@ void output_object(PycRef<PycObject> obj, PycModule* mod, int indent,
|
||||
case PycObject::TYPE_SHORT_ASCII:
|
||||
case PycObject::TYPE_SHORT_ASCII_INTERNED:
|
||||
iputs(pyc_output, indent, "");
|
||||
obj.cast<PycString>()->print(pyc_output, mod);
|
||||
obj.cast<PycString>()->dasPrintAndDecrypt(pyc_output, mod);
|
||||
pyc_output << "\n";
|
||||
break;
|
||||
case PycObject::TYPE_TUPLE:
|
||||
|
Reference in New Issue
Block a user