如何使用AutoHotkey(AHK)读写寄存器值?此前用ReadProcessMemory未成功
在AutoHotkey中读写寄存器值
AHK本身没有内置的寄存器读写功能,需要通过调用Windows原生API实现,以下分两种场景说明:
一、读写自身进程的寄存器
如果要读取当前AHK进程自身的寄存器,可通过动态生成汇编代码并执行的方式实现。比如获取64位环境下的RAX寄存器值:
示例:读取自身进程的RAX寄存器(64位AHK)
; 分配可执行内存 hMem := DllCall("VirtualAlloc", "Ptr", 0, "UInt", 32, "UInt", 0x1000, "UInt", 0x40, "Ptr") if (!hMem) { MsgBox, 内存分配失败 ExitApp } ; 写入汇编对应的机器码:将RAX的值存入指定内存,然后返回 ; 对应汇编指令: mov [rcx], rax; ret DllCall("RtlMoveMemory", "Ptr", hMem, "Ptr", &(0x488901C3), "UInt", 4) ; 调用这段汇编代码,获取RAX的值 result := 0 DllCall("CallWindowProc", "Ptr", hMem, "Ptr", &result, "Ptr", 0, "Ptr", 0, "Ptr", 0) MsgBox, RAX寄存器的值为: %result% ; 释放内存 DllCall("VirtualFree", "Ptr", hMem, "UInt", 0, "UInt", 0x8000)
说明
- 32位AHK需替换对应机器码,比如读取EAX寄存器的话,机器码为
0x8901C3(对应汇编:mov [ecx], eax; ret)。 - 扩展到其他寄存器只需修改对应的汇编机器码即可。
二、读写外部进程的寄存器
操作外部进程寄存器需要用到Windows调试API,步骤为:打开目标进程→获取线程句柄→挂起线程→读写寄存器上下文→恢复线程。
示例:读取外部进程的RCX寄存器(64位系统)
ProcessName := "notepad.exe" ; 目标进程名 ; 获取进程ID Process, Exist, %ProcessName% pid := ErrorLevel if (!pid) { MsgBox, 未找到目标进程 ExitApp } ; 打开进程(需要调试权限) hProcess := DllCall("OpenProcess", "UInt", 0x1F0FFF, "Int", 0, "UInt", pid, "Ptr") if (!hProcess) { MsgBox, 打开进程失败 ExitApp } ; 获取主线程ID hThreadSnap := DllCall("CreateToolhelp32Snapshot", "UInt", 0x2, "UInt", pid, "Ptr") THREADENTRY32 := Buffer(288, 0) ; 64位THREADENTRY32结构大小为288字节 NumPut(288, THREADENTRY32, 0, "UInt") if (!DllCall("Thread32First", "Ptr", hThreadSnap, "Ptr", &THREADENTRY32)) { MsgBox, 获取线程失败 DllCall("CloseHandle", "Ptr", hProcess) ExitApp } threadId := NumGet(THREADENTRY32, 12, "UInt") DllCall("CloseHandle", "Ptr", hThreadSnap) ; 打开线程 hThread := DllCall("OpenThread", "UInt", 0x200010, "Int", 0, "UInt", threadId, "Ptr") if (!hThread) { MsgBox, 打开线程失败 DllCall("CloseHandle", "Ptr", hProcess) ExitApp } ; 挂起线程 DllCall("SuspendThread", "Ptr", hThread) ; 初始化CONTEXT结构(64位,包含所有寄存器) CONTEXT := Buffer(1056, 0) ; 64位CONTEXT结构大小为1056字节 NumPut(0x10007, CONTEXT, 0, "UInt") ; CONTEXT_ALL标志 ; 获取寄存器上下文 if (!DllCall("GetThreadContext", "Ptr", hThread, "Ptr", &CONTEXT)) { MsgBox, 获取寄存器失败 DllCall("ResumeThread", "Ptr", hThread) DllCall("CloseHandle", "Ptr", hThread) DllCall("CloseHandle", "Ptr", hProcess) ExitApp } ; 读取RCX寄存器(64位CONTEXT中RCX的偏移量为0x88) rcxValue := NumGet(CONTEXT, 0x88, "UInt64") MsgBox, 目标进程RCX寄存器值为: %rcxValue% ; 恢复线程 DllCall("ResumeThread", "Ptr", hThread) ; 释放句柄 DllCall("CloseHandle", "Ptr", hThread) DllCall("CloseHandle", "Ptr", hProcess)
写入寄存器的说明
若要修改寄存器值,在获取CONTEXT后修改对应偏移的数值,再调用SetThreadContext即可:
; 将RCX的值修改为0x123456789ABCDEF NumPut(0x123456789ABCDEF, CONTEXT, 0x88, "UInt64") DllCall("SetThreadContext", "Ptr", hThread, "Ptr", &CONTEXT)
注意事项
- 操作外部进程需要管理员权限,否则可能因权限不足失败。
- 32位和64位进程的
CONTEXT结构大小、寄存器偏移不同,需根据目标进程位数调整。 - 挂起线程可能导致目标进程卡顿,操作完成后务必恢复线程。
内容的提问来源于stack exchange,提问作者daehyun
相关产品推荐
相关产品推荐

