這個鏈接給出了一個在 Linux 平臺上用 Python 執行 asm 的好例子,但我不知道如何在 Windows 上呼叫一個帶有回傳值的 asm func,你能告訴我怎么做或者給我一個例子嗎?
import ctypes
import mmap
buf = mmap.mmap(-1, mmap.PAGESIZE, prot=mmap.PROT_READ | mmap.PROT_WRITE | mmap.PROT_EXEC)
ftype = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int)
fpointer = ctypes.c_void_p.from_buffer(buf)
f = ftype(ctypes.addressof(fpointer))
buf.write(
b'\x8b\xc7' # mov eax, edi
b'\x83\xc0\x01' # add eax, 1
b'\xc3' # ret
)
r = f(42)
print(r)
del fpointer
buf.close()
uj5u.com熱心網友回復:
好吧,Unix 和 Windows 作業系統之間存在多重差異,所以這種低級的東西一般都附加在平臺上。
讓我們從匯編清單開始。
mov eax, edi
add eax, 1
ret
此代碼專門為 Unix OS 撰寫。為什么?因為假設第一個引數使用edi暫存器傳遞。在 Windows 系統中,第一個引數使用 傳遞ecx,因此 Windows 系統的正確程式集是:
mov eax, ecx
add eax, 1
ret
因此,修補了“已編譯”程式集:
asm_function = (
b'\x8b\xc1' # mov eax, ecx
b'\x83\xc0\x01' # add eax, 1
b'\xc3' # ret
)
關于mmap. 我試圖讓它作業,但任何嘗試都以訪問沖突訊息告終。我什至嘗試使用但 WinAPI 函式失敗并顯示( )錯誤代碼來設定PAGE_EXECUTE_READWRITE對分配(使用mmap())記憶體的保護。VirtualProtect()ERROR_INVALID_PARAMETER0x57
由于我無法使其作業,nmap為什么不向下一層并使用 WinAPI 分配記憶體?這很簡單,我們只需要呼叫VirtualAlloc()分配記憶體RtlMoveMemory()并將“預編譯”程式集復制到這個分配的記憶體。
我們需要修補默認argtypes和restypeofctypes.windll.kernel32.VirtualAlloc并ctypes.windll.kernel32.RtlMoveMemory匹配來自 MSDN 的簽名。我們必須這樣做,因為在 x64 系統上指標是 64 位的,但默認回傳值是 32 位,所以回傳的地址VirtualAlloc()不會被正確處理。特別感謝lifemaker ,他/她在回答中指出了這一點。
最終代碼:
import ctypes
asm_function = (
b'\x8b\xc1' # mov eax, ecx
b'\x83\xc0\x01' # add eax, 1
b'\xc3' # ret
)
# https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualalloc#MEM_COMMIT
MEM_COMMIT = 0x00001000
# https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualalloc#MEM_RESERVE
MEM_RESERVE = 0x00002000
# https://docs.microsoft.com/en-us/windows/win32/memory/memory-protection-constants#PAGE_EXECUTE_READWRITE
PAGE_EXECUTE_READWRITE = 0x40
# https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualalloc
ctypes.windll.kernel32.VirtualAlloc.argtypes = (
ctypes.c_void_p, # LPVOID
ctypes.c_size_t, # SIZE_T
ctypes.c_long, # DWORD
ctypes.c_long, # DWORD
)
ctypes.windll.kernel32.VirtualAlloc.restype = ctypes.c_void_p # LPVOID
memory_buffer = ctypes.windll.kernel32.VirtualAlloc(
0, # lpAddress - NULL
len(asm_function), # dwSize
MEM_COMMIT | MEM_RESERVE, # flAllocationType
PAGE_EXECUTE_READWRITE # flProtect
)
if not memory_buffer: # VirtualAlloc returned NULL
print("VirtualAlloc call failed. Error code:", ctypes.GetLastError())
exit(-1)
c_buffer = ctypes.c_char_p(asm_function)
# https://docs.microsoft.com/en-us/windows/win32/devnotes/rtlmovememory
ctypes.windll.kernel32.RtlMoveMemory.argtypes = (
ctypes.c_void_p, # VOID*
ctypes.c_void_p, # VOID*
ctypes.c_size_t # SIZE_T
)
ctypes.windll.kernel32.RtlMoveMemory(
memory_buffer, # Destination
c_buffer, # Source
len(asm_function) # Length
)
f = ctypes.cast(
memory_buffer,
ctypes.CFUNCTYPE(
ctypes.c_int, # return type
ctypes.c_int # argument type
)
)
r = f(42)
print(r)
PS如果有人會添加答案,我將不勝感激如何使用mmap.
You can help my country, check my profile info.
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/448717.html
下一篇:在遠程服務上復制檔案的功能
