如何使用Python反汇编器阻止函数执行打印操作?
Alright, let's figure out how to block that print output using Python's dis module and bytecode manipulation. Here's a straightforward breakdown based on your function and its disassembly:
First, let's recap your original function and its relevant disassembly for context:
import sys def game_on(): def other_function(): print('Statement within a another function') print("Hello World") sys.exit() print("Statement after sys.exit")
Relevant Original Disassembly
10 12 LOAD_GLOBAL 0 (print) 15 LOAD_CONST 3 ('Hello World') 18 CALL_FUNCTION 1 (...)
Step-by-Step Solution to Disable the Print Call
To stop print("Hello World") from executing, we need to modify the bytecode of the game_on function to either skip the print-related instructions or replace them with no-ops. Here's how to do it:
Access and modify the function's bytecode
Python function bytecode is stored in the immutable__code__.co_codeattribute. We'll convert this to a mutablebytearrayto make edits.Target the right instructions
Looking at the disassembly:- The
LOAD_GLOBAL(loading theprintfunction) starts at offset 12 LOAD_CONST(loading the "Hello World" string) is at offset 15CALL_FUNCTION(executing the print call) is at offset 18
We can either replace these instructions with
NOP(no-operation) or jump past them entirely.- The
Implement the bytecode edit
Here's a working example usingNOPreplacements:
import sys import dis import types def game_on(): def other_function(): print('Statement within a another function') print("Hello World") sys.exit() print("Statement after sys.exit") # Get the original code object original_code = game_on.__code__ # Convert to mutable bytearray for editing modified_bytecode = bytearray(original_code.co_code) # Replace print-related opcodes with NOP (opcode 9) # Offset 12: LOAD_GLOBAL -> NOP modified_bytecode[12] = dis.opmap['NOP'] modified_bytecode[13] = 0 # Argument for NOP doesn't matter # Offset 14: LOAD_CONST -> NOP (adjusted for 2-byte instruction alignment) modified_bytecode[14] = dis.opmap['NOP'] modified_bytecode[15] = 0 # Offset 16: CALL_FUNCTION -> NOP modified_bytecode[16] = dis.opmap['NOP'] modified_bytecode[17] = 0 # Offset 18: POP_TOP (cleanup after print) -> NOP modified_bytecode[18] = dis.opmap['NOP'] modified_bytecode[19] = 0 # Create a new code object with the modified bytecode new_code = types.CodeType( original_code.co_argcount, original_code.co_posonlyargcount, original_code.co_kwonlyargcount, original_code.co_nlocals, original_code.co_stacksize, original_code.co_flags, bytes(modified_bytecode), original_code.co_consts, original_code.co_names, original_code.co_varnames, original_code.co_filename, original_code.co_name, original_code.co_qualname, original_code.co_lnotab, original_code.co_freevars, original_code.co_cellvars ) # Assign the new code object back to the function game_on.__code__ = new_code # Test it out game_on() # Won't print "Hello World" anymore, just exits
Alternative: Jump Past the Print Call
A more efficient approach is to use a JUMP_FORWARD instruction to skip the entire print block. For example:
# Replace LOAD_GLOBAL with JUMP_FORWARD to skip 8 bytes (past the print call) modified_bytecode[12] = dis.opmap['JUMP_FORWARD'] modified_bytecode[13] = 8 # Jump 8 bytes to reach the sys.exit() instruction
This avoids executing the print-related instructions entirely instead of running no-ops.
内容的提问来源于stack exchange,提问作者Dart Feld

