利用AHK读写游戏内存也是很容易的,可以先用金山游侠或者CE搜索出要读写的内存地址,然后使用AHK读写它。当然难点在于搜索出准确的内存地址,那才是高手的拿手好戏。
;----------------------------------
; AHK读写游戏内存的函数 By FeiYue
;
; 中途读取(或写入)N级指针地址时不应该设置“字节”参数,
; 但是最后读取的数值需要准确指明“字节”参数,读取1、2、4、8字节的正整数值。
; 如果最后读取的是负数或小数或字符串,还需要指明“类型”或“编码”参数。
; 类型参数可以使用Char(1字节)、Short(2字节)、Int(4字节)
; 、Float(4字节)、Double(8字节)、Str(N字节,可以加编码)。
;
; 读值(进程ID或进程名, 目标地址, 字节="", 类型="", 编码="")
; 写值(进程ID或进程名, 目标地址, 写入值, 字节="", 类型="", 编码="")
;----------------------------------
F1::
程序名 := "Loginp.exe"
基址 := 0x01c4c5a8
血偏移 := 0x15c
写入值 := 15000
读取值:=读值(程序名, 读值(程序名,基址)+血偏移, 4)
MsgBox, 4096, 提示, % "写入前读取值为:" 读取值
写值(程序名, 读值(程序名,基址)+血偏移, 写入值, 4)
读取值:=读值(程序名, 读值(程序名,基址)+血偏移, 4)
MsgBox, 4096, 提示, % "写入后读取值为:" 读取值
return
;======== 下面是函数 ========
; 中途读取(或写入)N级指针地址时不应该设置“字节”参数,
; 但是最后读取的数值需要准确指明“字节”参数,读取1、2、4、8字节的正整数值。
; 如果最后读取的是负数或小数或字符串,还需要指明“类型”或“编码”参数。
; 类型参数可以使用Char(1字节)、Short(2字节)、Int(4字节)
; 、Float(4字节)、Double(8字节)、Str(N字节,可以加编码)。
读值(进程ID或进程名, 目标地址, 字节="", 类型="", 编码="")
{
static buf, type:={1:"uchar", 2:"ushort", 4:"uint", 8:"int64"}
;------------------
Process, Exist, %进程ID或进程名%
if !(PID:=ErrorLevel)
Throw "获取进程ID失败"
;------------------
if !进程句柄:=DllCall("OpenProcess"
, "UInt",0x001F0FFF, "UInt",0, "UInt",PID, "Ptr")
Throw "获取进程句柄失败"
;------------------
字节:=字节 ? 字节 : (!A_Is64bitOS) ? 4 : DllCall("IsWow64Process"
, "Ptr",进程句柄, "IntP",IsWow64)*0+IsWow64 ? 4 : 8
类型:=类型 ? 类型 : type[字节]
VarSetCapacity(buf, (字节<8?8:字节), 0)
;------------------
if !DllCall("ReadProcessMemory", "Ptr",进程句柄
, "Ptr",目标地址, "Ptr",&buf, "UInt",字节, "UInt",0)
Throw "读取内存值失败" DllCall("CloseHandle","Ptr",进程句柄)
;------------------
if !DllCall("CloseHandle", "Ptr",进程句柄)
Throw "关闭进程句柄失败"
;------------------
return (类型!="Str") ? NumGet(buf, 类型)
: (编码="") ? StrGet(&buf, 字节)
: StrGet(&buf, 字节, 编码)
}
写值(进程ID或进程名, 目标地址, 写入值, 字节="", 类型="", 编码="")
{
static buf, type:={1:"uchar", 2:"ushort", 4:"uint", 8:"int64"}
;------------------
Process, Exist, %进程ID或进程名%
if !(PID:=ErrorLevel)
Throw "获取进程ID失败"
;------------------
if !进程句柄:=DllCall("OpenProcess"
, "UInt",0x001F0FFF, "UInt",0, "UInt",PID, "Ptr")
Throw "获取进程句柄失败"
;------------------
字节:=字节 ? 字节 : (!A_Is64bitOS) ? 4 : DllCall("IsWow64Process"
, "Ptr",进程句柄, "IntP",IsWow64)*0+IsWow64 ? 4 : 8
类型:=类型 ? 类型 : type[字节]
VarSetCapacity(buf, (字节<8?8:字节), 0)
;------------------
(类型!="Str") ? NumPut(写入值, buf, 类型)
: (编码="") ? StrPut(写入值, &buf, 字节)
: StrPut(写入值, &buf, 字节, 编码)
;------------------
if !DllCall("VirtualProtectEx", "Ptr",进程句柄
, "Ptr",目标地址, "UInt",字节, "UInt",0x04, "UInt*",0)
Throw "修改权限失败" DllCall("CloseHandle","Ptr",进程句柄)
;------------------
if !DllCall("WriteProcessMemory", "Ptr",进程句柄
, "Ptr",目标地址, "Ptr",&buf, "UInt",字节, "UInt",0)
Throw "写入内存值失败" DllCall("CloseHandle","Ptr",进程句柄)
;------------------
if !DllCall("CloseHandle", "Ptr",进程句柄)
Throw "关闭进程句柄失败"
;------------------
return 目标地址+字节
}
提权() ; 有可能需要
{
static PROCESS_QUERY_INFORMATION := 0x400
, TOKEN_ADJUST_PRIVILEGES := 0x20
, SE_PRIVILEGE_ENABLED := 0x2
hProc := DllCall("OpenProcess", "UInt",PROCESS_QUERY_INFORMATION
, "Int",0, "UInt",DllCall("GetCurrentProcessId"), "Ptr")
DllCall("Advapi32\OpenProcessToken", "Ptr",hProc
, "UInt",TOKEN_ADJUST_PRIVILEGES, "PtrP", token)
DllCall("Advapi32\LookupPrivilegeValue"
, "Ptr",0, "Str","SeDebugPrivilege", "Int64P",luid)
VarSetCapacity(TOKEN_PRIVILEGES, 16, 0)
NumPut(1, TOKEN_PRIVILEGES, "UInt")
NumPut(luid, TOKEN_PRIVILEGES, 4, "Int64")
NumPut(SE_PRIVILEGE_ENABLED, TOKEN_PRIVILEGES, 12, "UInt")
DllCall("Advapi32\AdjustTokenPrivileges", "Ptr",token
, "Int",0, "Ptr",&TOKEN_PRIVILEGES, "Int",0, "Ptr",0, "Ptr",0)
res := A_LastError
DllCall("CloseHandle", "Ptr",token)
DllCall("CloseHandle", "Ptr",hProc)
Return res
}
虽然看不懂,但感觉也是很厉害
好!
感谢分享
多指针没有效果,最多只能偏移一次,例如ce第八关4级指针读取不了数据