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,
|
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) {
|
if (obj == NULL) {
|
||||||
pyc_output << "<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_ASCII_INTERNED:
|
||||||
case PycObject::TYPE_SHORT_ASCII:
|
case PycObject::TYPE_SHORT_ASCII:
|
||||||
case PycObject::TYPE_SHORT_ASCII_INTERNED:
|
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;
|
break;
|
||||||
case PycObject::TYPE_TUPLE:
|
case PycObject::TYPE_TUPLE:
|
||||||
case PycObject::TYPE_SMALL_TUPLE:
|
case PycObject::TYPE_SMALL_TUPLE:
|
||||||
@@ -362,7 +364,7 @@ void bc_disasm(std::ostream& pyc_output, PycRef<PycCode> code, PycModule* mod,
|
|||||||
try {
|
try {
|
||||||
auto constParam = code->getConst(operand);
|
auto constParam = code->getConst(operand);
|
||||||
formatted_print(pyc_output, "%d: ", 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 &) {
|
} catch (const std::out_of_range &) {
|
||||||
formatted_print(pyc_output, "%d <INVALID>", operand);
|
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,
|
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_next(PycBuffer& source, PycModule* mod, int& opcode, int& operand, int& pos);
|
||||||
void bc_disasm(std::ostream& pyc_output, PycRef<PycCode> code, PycModule* mod,
|
void bc_disasm(std::ostream& pyc_output, PycRef<PycCode> code, PycModule* mod,
|
||||||
int indent, unsigned flags);
|
int indent, unsigned flags);
|
||||||
|
@@ -15,8 +15,9 @@ def general_aes_ctr_decrypt(data: bytes, key: bytes, nonce: bytes) -> bytes:
|
|||||||
return cipher.decrypt(data)
|
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')
|
logger = logging.getLogger('shot')
|
||||||
|
output_dir: str = args.output_dir or args.directory
|
||||||
for path, data in sequences:
|
for path, data in sequences:
|
||||||
try:
|
try:
|
||||||
serial_number = data[2:8].decode('utf-8')
|
serial_number = data[2:8].decode('utf-8')
|
||||||
@@ -28,6 +29,7 @@ def decrypt_process(runtimes: dict[str, RuntimeInfo], sequences: list[tuple[str,
|
|||||||
if not os.path.exists(dest_dir):
|
if not os.path.exists(dest_dir):
|
||||||
os.makedirs(dest_dir)
|
os.makedirs(dest_dir)
|
||||||
|
|
||||||
|
if args.export_raw_data:
|
||||||
with open(dest_path + '.1shot.raw', 'wb') as f:
|
with open(dest_path + '.1shot.raw', 'wb') as f:
|
||||||
f.write(data)
|
f.write(data)
|
||||||
|
|
||||||
@@ -63,7 +65,7 @@ def decrypt_process(runtimes: dict[str, RuntimeInfo], sequences: list[tuple[str,
|
|||||||
for line in stderr:
|
for line in stderr:
|
||||||
if line.startswith('Warning'):
|
if line.startswith('Warning'):
|
||||||
logger.warning(f'STDERR {line} ({path})')
|
logger.warning(f'STDERR {line} ({path})')
|
||||||
else:
|
elif not line.startswith('Unsupported opcode:') or args.show_err_opcode:
|
||||||
logger.error(f'STDERR {line} ({path})')
|
logger.error(f'STDERR {line} ({path})')
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f'Decrypt failed: {e} ({path})')
|
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',
|
help='save output files in another directory instead of in-place, with folder structure remain unchanged',
|
||||||
type=str,
|
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()
|
return parser.parse_args()
|
||||||
|
|
||||||
|
|
||||||
@@ -145,8 +157,7 @@ def main():
|
|||||||
if not handled \
|
if not handled \
|
||||||
and specified_runtime is None \
|
and specified_runtime is None \
|
||||||
and file_name.startswith('pyarmor_runtime') \
|
and file_name.startswith('pyarmor_runtime') \
|
||||||
and not file_name.endswith(('.lnk', '.i64', '.idb', '.id0', '.id1',
|
and file_name.endswith(('.pyd', '.so', '.dylib')):
|
||||||
'.id2', '.nam', '.til', '.bak')):
|
|
||||||
try:
|
try:
|
||||||
new_runtime = RuntimeInfo(file_path)
|
new_runtime = RuntimeInfo(file_path)
|
||||||
runtimes[new_runtime.serial_number] = new_runtime
|
runtimes[new_runtime.serial_number] = new_runtime
|
||||||
@@ -189,7 +200,7 @@ def main():
|
|||||||
# TODO: is pyc or single marshalled binary?
|
# TODO: is pyc or single marshalled binary?
|
||||||
|
|
||||||
# print(runtimes, [(i[0], i[1][:16]) for i in sequences], args.output_dir or args.directory)
|
# 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__':
|
if __name__ == '__main__':
|
||||||
|
@@ -2,6 +2,7 @@
|
|||||||
#include "pyc_module.h"
|
#include "pyc_module.h"
|
||||||
#include "data.h"
|
#include "data.h"
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
#include "plusaes.hpp"
|
||||||
|
|
||||||
static bool check_ascii(const std::string& data)
|
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 ? '"' : '\'');
|
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,
|
void print(std::ostream& stream, class PycModule* mod, bool triple = false,
|
||||||
const char* parent_f_string_quote = nullptr);
|
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:
|
private:
|
||||||
std::string m_value;
|
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:
|
||||||
case PycObject::TYPE_SHORT_ASCII_INTERNED:
|
case PycObject::TYPE_SHORT_ASCII_INTERNED:
|
||||||
iputs(pyc_output, indent, "");
|
iputs(pyc_output, indent, "");
|
||||||
obj.cast<PycString>()->print(pyc_output, mod);
|
obj.cast<PycString>()->dasPrintAndDecrypt(pyc_output, mod);
|
||||||
pyc_output << "\n";
|
pyc_output << "\n";
|
||||||
break;
|
break;
|
||||||
case PycObject::TYPE_TUPLE:
|
case PycObject::TYPE_TUPLE:
|
||||||
|
Reference in New Issue
Block a user