You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 13:09:26