The LyScript plug-in implements the batch search function for specific assembly instruction fragments. The user passes in an assembly instruction list, and then loops through all instruction features in the list. If found, the memory address of the instruction is returned.
- Plug-in address: https://github.com/lyshark/Ly...
Get the machine code of the assembly instruction: This function is mainly realized to get the machine code corresponding to the assembly instruction passed in by the user. You can implement this code in this way.
from LyScript32 import MyDebug if __name__ == "__main__": dbg = MyDebug() connect_flag = dbg.connect() print("Connection Status: {}".format(connect_flag)) addr = dbg.create_alloc(1024) print("heap space: {}".format(hex(addr))) asm_size = dbg.assemble_code_size("mov eax,1") print("Assembly code occupies bytes: {}".format(asm_size)) write = dbg.assemble_write_memory(addr,"mov eax,1") byte_code = bytearray() for index in range(0,asm_size): read = dbg.read_memory_byte(addr + index) print("{:02x} ".format(read),end="") dbg.delete_alloc(addr)
Encapsulate the above code interface, implement get_opcode_from_assemble(), the user passes in the assembly instruction, and obtains the machine code corresponding to the instruction.
from LyScript32 import MyDebug # Pass in the assembly code to get the corresponding machine code def get_opcode_from_assemble(dbg_ptr,asm): byte_code = bytearray() addr = dbg_ptr.create_alloc(1024) if addr != 0: asm_size = dbg_ptr.assemble_code_size(asm) # print("Assembly code occupies bytes: {}".format(asm_size)) write = dbg_ptr.assemble_write_memory(addr,asm) if write == True: for index in range(0,asm_size): read = dbg_ptr.read_memory_byte(addr + index) # print("{:02x} ".format(read),end="") byte_code.append(read) dbg_ptr.delete_alloc(addr) return byte_code else: return bytearray(0) if __name__ == "__main__": dbg = MyDebug() connect_flag = dbg.connect() print("Connection Status: {}".format(connect_flag)) # Get assembly code byte_array = get_opcode_from_assemble(dbg,"xor eax,eax") for index in byte_array: print(hex(index),end="") print() # assemble a sequence asm_list = ["xor eax,eax", "xor ebx,ebx", "mov eax,1"] for index in asm_list: byte_array = get_opcode_from_assemble(dbg, index) for index in byte_array: print(hex(index),end="") print() dbg.close()
Run the above code to find the memory address that meets the conditions.
Batch search for disassembly code: Similar to searching for machine code, this function implements the search for all instruction sets in the code segment, whether it exists in the matching list, and returns the address if it exists.
from LyScript32 import MyDebug if __name__ == "__main__": dbg = MyDebug() dbg.connect() local_base_start = dbg.get_local_base() local_base_end = local_base_start + dbg.get_local_size() print("start address: {} --> end address: {}".format(hex(local_base_start),hex(local_base_end))) search_asm = ['test eax,eax', 'cmp esi, edi', 'pop edi', 'cmp esi,edi', 'jmp esp'] while local_base_start <= local_base_end: disasm = dbg.get_disasm_one_code(local_base_start) print("address: 0x{:08x} --> disassembly: {}".format(local_base_start,disasm)) # find instructions for index in range(0, len(search_asm)): if disasm == search_asm[index]: print("address: {} --> disassembly: {}".format(hex(local_base_start), disasm)) # increment counter local_base_start = local_base_start + dbg.get_disasm_operand_size(local_base_start) dbg.close()
Search disassembly list features: Use python to implement the method, scan the memory range through a specific method, and output the specific memory address of the instruction if the instruction set sequence we need appears.
from LyScript32 import MyDebug # Pass in the assembly code to get the corresponding machine code def get_opcode_from_assemble(dbg_ptr,asm): byte_code = bytearray() addr = dbg_ptr.create_alloc(1024) if addr != 0: asm_size = dbg_ptr.assemble_code_size(asm) # print("Assembly code occupies bytes: {}".format(asm_size)) write = dbg_ptr.assemble_write_memory(addr,asm) if write == True: for index in range(0,asm_size): read = dbg_ptr.read_memory_byte(addr + index) # print("{:02x} ".format(read),end="") byte_code.append(read) dbg_ptr.delete_alloc(addr) return byte_code else: return bytearray(0) # Search for the machine code and return it if it exists def SearchOpCode(dbg_ptr, Search): # Search machine code and convert to list op_code = [] for index in Search: byte_array = get_opcode_from_assemble(dbg, index) for index in byte_array: op_code.append(hex(index)) # print("Machine code list: {}".format(op_code)) # Convert a list of machine codes to a string # 1. First convert to a list of strings x = [str(i) for i in op_code] # 2. Convert the list of strings to strings # search_code = ' '.join(x).replace("0x","") search_code = [] # Add less than three leading 0s for l in range(0,len(x)): if len(x[l]) <= 3: # If it is less than 3 digits, add 0 in front # print(''.join(x[l]).replace("0x","").zfill(2)) search_code.append(''.join(x[l]).replace("0x","").zfill(2)) else: search_code.append(''.join(x[l]).replace("0x", "")) # 3. Turn into a string search_code = ' '.join(search_code).replace("0x", "") print("search string: {}".format(search_code)) # Invoke the search command ref = dbg.scan_memory_one(search_code) if ref != None or ref != 0: return ref else: return 0 return 0 if __name__ == "__main__": dbg = MyDebug() connect_flag = dbg.connect() print("Connection Status: {}".format(connect_flag)) # Search for a sequence of instructions to quickly find and build exploit code SearchCode = [ ["pop ecx", "pop ebp", "ret", "push ebp"], ["push ebp", "mov ebp,esp"], ["mov ecx, dword ptr ds:[eax+0x3C]", "add ecx, eax"] ] # Retrieve memory instruction set for item in range(0, len(SearchCode)): Search = SearchCode[item] ret = SearchOpCode(dbg, Search) print("The memory where the searched instruction is located: {}".format(hex(ret))) dbg.close()
In the above code, the first function get_opcode_from_assemble(dbg_ptr,asm) is used to obtain the machine code from the assembly instruction passed in by the user, and the function SearchOpCode(dbg_ptr, Search) is used to convert the assembly list passed in by the user into a continuous string .
1. Fragment 1 realizes converting the machine code into a hexadecimal array
op_code = [] for index in Search: byte_array = get_opcode_from_assemble(dbg, index) for index in byte_array: op_code.append(hex(index))
2. Fragment 2 removes the 0x prefix from the hexadecimal machine code, and judges whether the hexadecimal number is less than or equal to 3 digits, and if so, adds 0 to the output prefix, otherwise directly outputs to the search_code variable.
# Convert a list of machine codes to a string # 1. First convert to a list of strings x = [str(i) for i in op_code] # 2. Convert the list of strings to strings # search_code = ' '.join(x).replace("0x","") search_code = [] # Add less than three leading 0s for l in range(0,len(x)): if len(x[l]) <= 3: # If it is less than 3 digits, add 0 in front # print(''.join(x[l]).replace("0x","").zfill(2)) search_code.append(''.join(x[l]).replace("0x","").zfill(2)) else: search_code.append(''.join(x[l]).replace("0x", ""))
3. Fragment 3, finally call the search machine code command, first convert the string list into a string, and then call dbg.scan_memory_one(search_code) to complete the entire search process.
search_code = ' '.join(search_code).replace("0x", "") print("search string: {}".format(search_code)) # Invoke the search command ref = dbg.scan_memory_one(search_code) if ref != None or ref != 0: return ref else: return 0 return 0
In the final call, the user passes in a two-dimensional list, and then searches for all eligible memory addresses in the list in turn.