Bạn có thể biên dịch python thành assembly không?

Tiết lộ. Bài đăng này có thể chứa các liên kết liên kết, nghĩa là khi bạn nhấp vào liên kết và mua hàng, chúng tôi sẽ nhận được hoa hồng

Bộ xử lý thực thi mã Hợp ngữ, là ngôn ngữ lập trình cấp thấp sử dụng trực tiếp thanh ghi và bộ nhớ, bên trong tệp thực thi gốc. Mã hội được lưu trữ ở dạng đã lắp ráp, dưới dạng dữ liệu nhị phân, có hướng dẫn sử dụng bộ xử lý chỉ định cách mỗi lệnh có thể được mã hóa thành byte dữ liệu

Tháo rời là quá trình ngược lại của lắp ráp, các byte dữ liệu được phân tích cú pháp và dịch thành hướng dẫn lắp ráp (người dùng dễ đọc hơn)

Các kiến ​​trúc bộ xử lý khác nhau có thể có các tập lệnh khác nhau và một bộ xử lý chỉ có thể thực thi các lệnh hợp ngữ trong tập lệnh của chính nó, để chạy mã dành cho các kiến ​​trúc khác nhau, chúng ta cần sử dụng trình giả lập, là chương trình dịch mã cho các cấu trúc không được hỗ trợ

Có nhiều tình huống trong đó việc lắp ráp, tháo rời hoặc mô phỏng mã cho các kiến ​​trúc khác nhau có thể hữu ích, một trong những sở thích chính là dành cho việc học (hầu hết các trường đại học dạy lắp ráp MIPS) để chạy và thử nghiệm các chương trình được viết cho các thiết bị khác nhau như bộ định tuyến (làm mờ, v.v. ), và cho kỹ thuật đảo ngược

Trong hướng dẫn này, chúng ta sẽ lắp ráp, tháo rời và mô phỏng mã hợp ngữ được viết cho ARM bằng công cụ Keystone, công cụ Capstone và công cụ Unicorn, là các khung cung cấp các ràng buộc Python thuận tiện để thao tác mã hợp ngữ, chúng hỗ trợ các kiến ​​trúc khác nhau (x86, ARM, MIPS,

Đầu tiên, hãy cài đặt ba khung này

pip3 install keystone-engine capstone unicorn

Để trình diễn hướng dẫn này, chúng tôi sẽ sử dụng một hàm giai thừa được triển khai trong hợp ngữ ARM, tập hợp mã và mô phỏng nó

Chúng tôi cũng sẽ phân tách một chức năng x86 (để cho thấy cách dễ dàng xử lý nhiều kiến ​​trúc)

Lắp ráp CÁNH TAY

Chúng tôi bắt đầu bằng cách nhập những gì chúng tôi cần cho lắp ráp ARM

# We need to emulate ARM
from unicorn import Uc, UC_ARCH_ARM, UC_MODE_ARM, UcError
# for accessing the R0 and R1 registers
from unicorn.arm_const import UC_ARM_REG_R0, UC_ARM_REG_R1
# We need to assemble ARM code
from keystone import Ks, KS_ARCH_ARM, KS_MODE_ARM, KsError

Hãy viết mã hợp ngữ ARM của chúng ta, tính toán giai thừa (

# We need to emulate ARM
from unicorn import Uc, UC_ARCH_ARM, UC_MODE_ARM, UcError
# for accessing the R0 and R1 registers
from unicorn.arm_const import UC_ARM_REG_R0, UC_ARM_REG_R1
# We need to assemble ARM code
from keystone import Ks, KS_ARCH_ARM, KS_MODE_ARM, KsError
0), trong đó
# We need to emulate ARM
from unicorn import Uc, UC_ARCH_ARM, UC_MODE_ARM, UcError
# for accessing the R0 and R1 registers
from unicorn.arm_const import UC_ARM_REG_R0, UC_ARM_REG_R1
# We need to assemble ARM code
from keystone import Ks, KS_ARCH_ARM, KS_MODE_ARM, KsError
0 là một thanh ghi đầu vào

ARM_CODE = """
// n is r0, we will pass it from python, ans is r1
mov r1, 1       	// ans = 1
loop:
cmp r0, 0       	// while n >= 0:
mulgt r1, r1, r0	//   ans *= n
subgt r0, r0, 1 	//   n = n - 1
bgt loop        	// 
                	// answer is in r1
"""

Hãy lắp ráp mã Hợp ngữ ở trên (chuyển đổi nó thành mã byte)

print("Assembling the ARM code")
try:
    # initialize the keystone object with the ARM architecture
    ks = Ks(KS_ARCH_ARM, KS_MODE_ARM)
    # Assemble the ARM code
    ARM_BYTECODE, _ = ks.asm(ARM_CODE)
	# convert the array of integers into bytes
    ARM_BYTECODE = bytes(ARM_BYTECODE)
    print(f"Code successfully assembled (length = {len(ARM_BYTECODE)})")
    print("ARM bytecode:", ARM_BYTECODE)
except KsError as e:
    print("Keystone Error: %s" % e)
    exit(1)

Hàm

# We need to emulate ARM
from unicorn import Uc, UC_ARCH_ARM, UC_MODE_ARM, UcError
# for accessing the R0 and R1 registers
from unicorn.arm_const import UC_ARM_REG_R0, UC_ARM_REG_R1
# We need to assemble ARM code
from keystone import Ks, KS_ARCH_ARM, KS_MODE_ARM, KsError
2 trả về một Trình biên dịch mã ở chế độ ARM, phương thức
# We need to emulate ARM
from unicorn import Uc, UC_ARCH_ARM, UC_MODE_ARM, UcError
# for accessing the R0 and R1 registers
from unicorn.arm_const import UC_ARM_REG_R0, UC_ARM_REG_R1
# We need to assemble ARM code
from keystone import Ks, KS_ARCH_ARM, KS_MODE_ARM, KsError
3 lắp ráp mã và trả về các byte cũng như số lượng lệnh mà nó đã lắp ráp

Mã byte hiện có thể được ghi trên vùng bộ nhớ và được thực thi bởi bộ xử lý ARM (hoặc được mô phỏng, trong trường hợp của chúng tôi)

________số 8_______

Trong đoạn mã trên, chúng tôi khởi tạo trình giả lập ở chế độ ARM, chúng tôi ánh xạ 2 MB bộ nhớ tại địa chỉ đã chỉ định (2*1024*1024 byte), chúng tôi ghi kết quả của quá trình lắp ráp vào vùng bộ nhớ được ánh xạ, chúng tôi đặt thanh ghi

# We need to emulate ARM
from unicorn import Uc, UC_ARCH_ARM, UC_MODE_ARM, UcError
# for accessing the R0 and R1 registers
from unicorn.arm_const import UC_ARM_REG_R0, UC_ARM_REG_R1
# We need to assemble ARM code
from keystone import Ks, KS_ARCH_ARM, KS_MODE_ARM, KsError
0 thành

Phương thức

# We need to emulate ARM
from unicorn import Uc, UC_ARCH_ARM, UC_MODE_ARM, UcError
# for accessing the R0 and R1 registers
from unicorn.arm_const import UC_ARM_REG_R0, UC_ARM_REG_R1
# We need to assemble ARM code
from keystone import Ks, KS_ARCH_ARM, KS_MODE_ARM, KsError
5 nhận đối số
# We need to emulate ARM
from unicorn import Uc, UC_ARCH_ARM, UC_MODE_ARM, UcError
# for accessing the R0 and R1 registers
from unicorn.arm_const import UC_ARM_REG_R0, UC_ARM_REG_R1
# We need to assemble ARM code
from keystone import Ks, KS_ARCH_ARM, KS_MODE_ARM, KsError
6 tùy chọn và số lượng hướng dẫn tối đa tùy chọn để mô phỏng, có thể hữu ích cho mã hộp cát hoặc giới hạn mô phỏng ở một phần nhất định của mã

Sau khi giả lập tính xong ta đọc nội dung của thanh ghi

# We need to emulate ARM
from unicorn import Uc, UC_ARCH_ARM, UC_MODE_ARM, UcError
# for accessing the R0 and R1 registers
from unicorn.arm_const import UC_ARM_REG_R0, UC_ARM_REG_R1
# We need to assemble ARM code
from keystone import Ks, KS_ARCH_ARM, KS_MODE_ARM, KsError
7, thanh ghi này chứa kết quả của việc giả lập, chạy code xuất ra kết quả như sau

Assembling the ARM code
Code successfully assembled (length = 20)
ARM bytecode: b'\x01\x10\xa0\xe3\x00\x00P\xe3\x91\x00\x01\xc0\x01\x00@\xc2\xfb\xff\xff\xca'
Emulating the ARM code
Emulation done. Below is the result
>>  R1 = 120

Ta được kết quả như mong đợi, giai thừa của 5 là 120

Tháo mã x86-64

Bây giờ nếu chúng ta có mã máy của x86 và chúng ta muốn phân tách nó, đoạn mã sau sẽ làm điều đó

# We need to emulate ARM and x86 code
from unicorn import Uc, UC_ARCH_X86, UC_MODE_64, UcError
# for accessing the RAX and RDI registers
from unicorn.x86_const import UC_X86_REG_RDI, UC_X86_REG_RAX
# We need to disassemble x86_64 code
from capstone import Cs, CS_ARCH_X86, CS_MODE_64, CsError

X86_MACHINE_CODE = b"\x48\x31\xc0\x48\xff\xc0\x48\x85\xff\x0f\x84\x0d\x00\x00\x00\x48\x99\x48\xf7\xe7\x48\xff\xcf\xe9\xea\xff\xff\xff"
# memory address where emulation starts
ADDRESS = 0x1000000
try:
      # Initialize the disassembler in x86 mode
      md = Cs(CS_ARCH_X86, CS_MODE_64)
      # iterate over each instruction and print it
      for instruction in md.disasm(X86_MACHINE_CODE, 0x1000):
            print("0x%x:\t%s\t%s" % (instruction.address, instruction.mnemonic, instruction.op_str))
except CsError as e:
      print("Capstone Error: %s" % e)

Chúng tôi khởi tạo trình dịch ngược mã ở chế độ x86-64, mã mã máy được cung cấp, lặp lại các hướng dẫn trong kết quả tháo gỡ và đối với mỗi lệnh, chúng tôi in lệnh và địa chỉ xảy ra

Điều này mang lại đầu ra sau

0x1000: xor     rax, rax
0x1003: inc     rax
0x1006: test    rdi, rdi
0x1009: je      0x101c
0x100f: cqo
0x1011: mul     rdi
0x1014: dec     rdi
0x1017: jmp     0x1006

Bây giờ hãy thử mô phỏng nó với công cụ Unicorn

try:
    # Initialize emulator in x86_64 mode
    mu = Uc(UC_ARCH_X86, UC_MODE_64)
    # map 2MB memory for this emulation
    mu.mem_map(ADDRESS, 2 * 1024 * 1024)
    # write machine code to be emulated to memory
    mu.mem_write(ADDRESS, X86_MACHINE_CODE)
    # Set the r0 register in the code to the number of 7
    mu.reg_write(UC_X86_REG_RDI, 7)
    # emulate code in infinite time & unlimited instructions
    mu.emu_start(ADDRESS, ADDRESS + len(X86_MACHINE_CODE))
    # now print out the R0 register
    print("Emulation done. Below is the result")
    rax = mu.reg_read(UC_X86_REG_RAX)
    print(">>> RAX = %u" % rax)
except UcError as e:
    print("Unicorn Error: %s" % e)

đầu ra

Emulation done. Below is the result
>>> RAX = 5040

Chúng tôi nhận được kết quả là 5040 và chúng tôi nhập 7. Nếu chúng ta xem kỹ mã hợp ngữ x86 này, chúng ta sẽ nhận thấy rằng mã này tính giai thừa của thanh ghi rdi (5040 là giai thừa của 7)

Phần kết luận

Ba khung điều khiển mã Assembly một cách thống nhất, như bạn có thể thấy trong mã giả lập x86-64 Assembly, thực sự giống với phiên bản giả lập ARM. Việc tháo rời và lắp ráp mã cũng được thực hiện theo cách tương tự với mọi kiến ​​trúc được hỗ trợ

Một điều cần lưu ý là trình giả lập Unicorn mô phỏng mã máy thô, nó không mô phỏng lệnh gọi Windows API, không phân tích cú pháp và mô phỏng các định dạng tệp như PE và ELF

Trong một số trường hợp, sẽ hữu ích khi mô phỏng toàn bộ hệ điều hành hoặc chương trình ở dạng trình điều khiển nhân hoặc tệp nhị phân dành cho một hệ điều hành khác, có một khung tuyệt vời được xây dựng trên Unicorn để xử lý những điều này

Sau khi thử nghiệm ba khung công tác Python, chúng tôi kết luận rằng thao tác với mã Hợp ngữ bằng Python rất dễ dàng, tính đơn giản của Python kết hợp với các giao diện Python thuận tiện và thống nhất do Keystone, Capstone và Unicorn cung cấp giúp dễ dàng, ngay cả đối với người mới bắt đầu, để lắp ráp,

Cuối cùng, nếu bạn là người mới bắt đầu và muốn học Python, tôi khuyên bạn nên tham gia khóa học Python For Everyone Coursera, trong đó bạn sẽ học được nhiều điều về Python. Bạn cũng có thể xem trang tài nguyên và khóa học của chúng tôi để xem các tài nguyên Python mà tôi đề xuất về các chủ đề khác nhau

Làm cách nào để chuyển đổi Python thành hợp ngữ?

Biên dịch python sang C, sau đó sử dụng trình biên dịch C mà bạn chọn để đưa nó xuống hợp ngữ . Ngoài ra, hãy sử dụng PyPy, chỉ định LLVM làm mục tiêu và sử dụng Trình biên dịch tĩnh LLVM để tạo ngôn ngữ hợp ngữ cho kiến ​​trúc mục tiêu của bạn.

Tập lệnh Python có thể được biên dịch không?

Mô-đun py_compile cung cấp chức năng tạo tệp mã byte từ tệp nguồn và một chức năng khác được sử dụng khi tệp nguồn mô-đun được gọi dưới dạng tập lệnh .

Hội có trình biên dịch không?

Ngôn ngữ biên dịch và thông dịch . Kết quả là một tệp chương trình có thể được chạy sau đó mà không cần tham khảo mã nguồn có thể đọc được của con người. a compiled language is translated directly into machine-readable binary code by a special program called a compiler. The result is a program file that can then be subsequently run without needing to refer to the human-readable source code.

Trình biên dịch có chuyển đổi sang hợp ngữ không?

Sự khác biệt giữa Trình biên dịch và Trình biên dịch