元旦闲着没事干,就找点有用的库存发一发吧。
如果你会使用CE之类的内存修改器,找到了数据地址又想通过ahk实现读写操作,那么这个库可以帮到你。
仅供学习,请勿用于非法用途。
下面的示例使用CE自带的教程, 注意需要以管理员权限运行代码。
读取,修改内存
首先需要打开你要读写的进程:
对应的代码是:
ps := RemoteProcess.FromProcessName("Tutorial-x86_64.exe") ; 通过进程名打开 ; ps := RemoteProcess.FromWindow("步骤 2 ahk_exe Tutorial-x86_64.exe") ; 通过窗口打开 ; ps := RemoteProcess.FromProcessId(0x000029F4) ; 通过pid打开
找到健康值的地址:
使用RemoteProcess可以这样读取:
health := ps.ReadNumber(0x00131590, "int") ; int对应4字节
过关条件是把健康调整为1000,可以这样写:
ps.WriteNumber(0x00131590, 1000, "int")
运行上面的代码后就能发现数值变成1000了:
其他数据类型也是一样的,仅仅就是换个参数,如单浮点用float表示,双浮点用double表示:
ps.WriteNumber(0x0013BF78, 5000, "float") ps.WriteNumber(0x0013BF80, 6000, "double")
多级指针
在CE教程的第8关中,需要用到基址和多级指针,如果你按照CE教程走,可以得到这样的结果:
读取最终的数据,使用RemoteProcess需要这么做:
ps := RemoteProcess.FromProcessName("Tutorial-x86_64.exe") ; 通过进程名打开 baseAddress := ps.GetModuleAddressByName("Tutorial-x86_64.exe") + 0x00306B00 ; 通过模块名获取基址 ptr := ps.TracePointer(baseAddress, 0x10, 0x18, 0, 0x18) ; 通过基址+偏移获取目标地址 health := ps.ReadNumber(ptr, "int")
有的时候基址是这样的:”THREADSTACK0″ – 000003C0, “THREADSTACK1″ + 00000210, 这时需要使用GetThreadStackAddress方法; 如果是”.data”这种段地址,用GetSectionAddressByName; 如果是函数地址,用GetFunctionAddressByName:
baseAddress := ps.GetThreadStackAddress(0) - 0x000003C0 baseAddress := ps.GetThreadStackAddress(1) + 0x00000210 baseAddress := ps.GetSectionAddressByName("User32.dll", ".data") baseAddress := ps.GetFunctionAddressByName("User32.dll", "MessageBoxW")
掌握以上几个方法基本就差不多了,下面放库, 为了方便运行,建议把下面两个库都放到lib文件夹
RemoteProcess.ahk
/* @Version 0.2 */ #Requires AutoHotkey v2.0.0 64-bit #Include <ToolHelp> CONST := CONST ?? {} CONST.PAGE_NOACCESS := 0x01, CONST.PAGE_READONLY := 0x02, CONST.PAGE_READWRITE := 0x04, CONST.PAGE_WRITECOPY := 0x08, CONST.PAGE_EXECUTE := 0x10, CONST.PAGE_EXECUTE_READ := 0x20, CONST.PAGE_EXECUTE_READWRITE := 0x40, CONST.PAGE_EXECUTE_WRITECOPY := 0x80, CONST.PAGE_GUARD := 0x100, CONST.PAGE_NOCACHE := 0x200, CONST.PAGE_WRITECOMBINE := 0x400, CONST.PAGE_GRAPHICS_NOACCESS := 0x0800, CONST.PAGE_GRAPHICS_READONLY := 0x1000, CONST.PAGE_GRAPHICS_READWRITE := 0x2000, CONST.PAGE_GRAPHICS_EXECUTE := 0x4000, CONST.PAGE_GRAPHICS_EXECUTE_READ := 0x8000, CONST.PAGE_GRAPHICS_EXECUTE_READWRITE := 0x10000, CONST.PAGE_GRAPHICS_COHERENT := 0x20000, CONST.PAGE_GRAPHICS_NOCACHE := 0x40000, CONST.PAGE_ENCLAVE_THREAD_CONTROL := 0x80000000, CONST.PAGE_REVERT_TO_FILE_MAP := 0x80000000, CONST.PAGE_TARGETS_NO_UPDATE := 0x40000000, CONST.PAGE_TARGETS_INVALID := 0x40000000, CONST.PAGE_ENCLAVE_UNVALIDATED := 0x20000000, CONST.PAGE_ENCLAVE_MASK := 0x10000000, CONST.PAGE_ENCLAVE_DECOMMIT := (CONST.PAGE_ENCLAVE_MASK | 0), CONST.PAGE_ENCLAVE_SS_FIRST := (CONST.PAGE_ENCLAVE_MASK | 1), CONST.PAGE_ENCLAVE_SS_REST := (CONST.PAGE_ENCLAVE_MASK | 2) CONST.MEM_COMMIT := 0x00001000, CONST.MEM_RESERVE := 0x00002000, CONST.MEM_REPLACE_PLACEHOLDER := 0x00004000, CONST.MEM_RESERVE_PLACEHOLDER := 0x00040000, CONST.MEM_RESET := 0x00080000, CONST.MEM_TOP_DOWN := 0x00100000, CONST.MEM_WRITE_WATCH := 0x00200000, CONST.MEM_PHYSICAL := 0x00400000, CONST.MEM_ROTATE := 0x00800000, CONST.MEM_DIFFERENT_IMAGE_BASE_OK := 0x00800000, CONST.MEM_RESET_UNDO := 0x01000000, CONST.MEM_LARGE_PAGES := 0x20000000, CONST.MEM_4MB_PAGES := 0x80000000, CONST.MEM_64K_PAGES := (CONST.MEM_LARGE_PAGES | CONST.MEM_PHYSICAL), CONST.MEM_UNMAP_WITH_TRANSIENT_BOOST := 0x00000001, CONST.MEM_COALESCE_PLACEHOLDERS := 0x00000001, CONST.MEM_PRESERVE_PLACEHOLDER := 0x00000002, CONST.MEM_DECOMMIT := 0x00004000, CONST.MEM_RELEASE := 0x00008000, CONST.MEM_FREE := 0x00010000 /* @Example Open a process ; You can open a process by process name, hwnd or pid ps := RemoteProcess.FromProcessName("explorer.exe") ps := RemoteProcess.FromWindow(WinExist("ahk_class Shell_TrayWnd")) ps := RemoteProcess.FromProcessId(WinGetPID("Program Manager")) @Example Converts the base address described by module name, segment name, function name, or THREADSTACKXX to a numeric address ps := RemoteProcess.FromWindow(WinExist("ahk_class Notepad")) MsgBox '"Kernel.dll": ' Format("{:#016x}", ps.GetModuleAddressByName("Kernel32.dll")) MsgBox '"User32.dll.data": ' Format("{:#016x}", ps.GetSectionAddressByName("User32.dll", ".data")) MsgBox '"User32.MessageBoxW": ' Format("{:#016x}", ps.GetFunctionAddressByName("User32.dll", "MessageBoxW")) MsgBox '"THREADSTACK0": ' Format("{:#016x}", ps.GetThreadStackAddress(0)) @Example Find the address of the data we need via base address and offsets, then read & write number from it ps := RemoteProcess.FromProcessName("TextInputHost.exe") ; In this case, the base address is "THREADSTACK0"-00000750 in CE ptr := ps.TracePointer(ps.GetThreadStackAddress(0) - 0x750, 0xC8, 0xC0, 0x300, 0x58, 0x8, 0xB0, 0, 0x1C0, 0x48, 0x18, 0x40, 0xF0) ; Read and Write a 32 bit integer MsgBox ps.ReadNumber(ptr, "int") ps.WriteNumber(ptr, 0, "int") MsgBox ps.ReadNumber(ptr, "int") @Example Read text from Notepad ps := RemoteProcess.FromWindow(WinExist("ahk_class Notepad")) ptr := ps.GetModuleAddressByName("textinputframework.dll") + 0xE83C0 MsgBox ps.ReadWString(ptr) @Example Call a function MsgBox RunWait("Notepad",,, &pid) f1::{ ps := RemoteProcess.FromProcessId(pid) pExitProcess := ps.GetFunctionAddressByName("Kernel32.dll", "ExitProcess") ps.CreateThread(pExitProcess, 123) } */ class RemoteProcess { static __TypeSize := {Char: 1, UChar: 1, Short: 2, UShort: 2, Int: 4, UInt: 4, Ptr: A_PtrSize, UPtr: A_PtrSize, Int64: 8, UInt64: 8, Float: 4, Double: 8} static FromProcessName(processname) { if !pid := ProcessExist(processname) throw Error("Cannot find the process.") return this.FromProcessId(pid) } static FromWindow(winTitle) { if !DllCall("GetWindowThreadProcessId", "ptr", WinExist(winTitle), "uint*", &processId := 0) throw OSError() return this.FromProcessId(processId) } static FromProcessId(processId) { if !hProcess := DllCall("OpenProcess", "uint", 0x1fffff, "int", false, "uint", processId, "ptr") throw OSError() return this(hProcess) } __New(hProcess) { this.Handle := hProcess DllCall("IsWow64Process2", "ptr", hProcess, "ushort*", &isWow64 := 0, "ushort*", 0) this.IsWow64 := isWow64 this.ProcessId := DllCall("GetProcessId", "ptr", hProcess, "uint") } __Delete() { DllCall("CloseHandle", "ptr", this.Handle) } Alloc(bytes, allocationType := CONST.MEM_COMMIT, protectType := CONST.PAGE_EXECUTE_READWRITE) { if !address := DllCall("VirtualAllocEx", "ptr", this.Handle, "ptr", 0, "ptr", bytes, "uint", allocationType, "uint", protectType, "ptr") throw OSError() return address } Free(address, bytes := 0, freeType := CONST.MEM_RELEASE) { if !DllCall("VirtualFreeEx", "ptr", this.Handle, "ptr", address, "uptr", bytes, "uint", freeType) throw OSError() } Protect(address, bytes, newProtectType) { if !DllCall("VirtualProtectEx", "ptr", this.Handle, "ptr", address, "uptr", bytes, "uint", newProtectType, "uint*", &oldProtectType := 0) throw OSError() return oldProtectType } CreateThread(address, param, &threadId := 0, closeHanlde := true) { if !hThread := DllCall("CreateRemoteThread", "ptr", this.Handle, "ptr", 0, "uptr", 0, "ptr", address, "ptr", param, "uint", 0, "uint*", &threadId, "ptr") throw OSError() if closeHanlde return DllCall("CloseHandle", "ptr", hThread) return hThread } ReadMemory(dest, src, bytes) { if !DllCall("ReadProcessMemory", "ptr", this.Handle, "ptr", src, "ptr", dest, "uptr", bytes, "uptr*", &bytesRead := 0) throw OSError() return bytesRead } ReadBuffer(address, bytes) { if !DllCall("ReadProcessMemory", "ptr", this.Handle, "ptr", address, "ptr", buf := Buffer(bytes), "uptr", bytes, "uptr*", &bytesRead := 0) throw OSError() if buf.Size != bytesRead buf.Size := bytesRead return buf } ReadNumber(address, type) { if !DllCall("ReadProcessMemory", "ptr", this.Handle, "ptr", address, type "*", &num := 0, "uptr", RemoteProcess.__TypeSize.%type%, "ptr", 0) throw OSError() return num } ReadString(address, cch := 0, encoding := "cp0") { offset := char := 0 if cch == 0 { buf := Buffer(1024) while DllCall("ReadProcessMemory", "ptr", this.Handle, "ptr", address, "char*", &char, "uptr", 2, "ptr", 0) && char != 0 { NumPut("char", char, buf, offset) ++address ++offset if offset == buf.Size buf.Size += 1024 } } else { buf := Buffer(cch) while A_Index < cch && DllCall("ReadProcessMemory", "ptr", this.Handle, "ptr", address, "char*", &char, "uptr", 2, "ptr", 0) && char != 0 { NumPut("char", char, buf, offset) ++address ++offset } } NumPut("char", 0, buf, offset) return StrGet(buf.Ptr, encoding) } ReadWString(address, cch := 0) { offset := char := 0 if cch == 0 { buf := Buffer(1024) while DllCall("ReadProcessMemory", "ptr", this.Handle, "ptr", address, "ushort*", &char, "uptr", 2, "ptr", 0) && char != 0 { NumPut("ushort", char, buf, offset) address += 2 offset += 2 if offset == buf.Size buf.Size += 1024 } } else { buf := Buffer(cch * 2) while A_Index < cch && DllCall("ReadProcessMemory", "ptr", this.Handle, "ptr", address, "short*", &char, "uptr", 2, "ptr", 0) && char != 0 { NumPut("short", char, buf, offset) address += 2 offset += 2 } } NumPut("ushort", 0, buf, offset) return StrGet(buf.Ptr, "utf-16") } WriteMemory(dest, src, bytes) { if !DllCall("WriteProcessMemory", "ptr", this.Handle, "ptr", dest, "ptr", src, "uptr", bytes, "ptr", 0) throw OSError() } WriteNumber(dest, number, type) { if !DllCall("WriteProcessMemory", "ptr", this.Handle, "ptr", dest, type "*", number, "uptr", RemoteProcess.__TypeSize.%type%, "ptr", 0) throw OSError() } WriteString(dest, str, encoding := "cp0") { if encoding = "cp0" || encoding = "" { if !DllCall("WriteProcessMemory", "ptr", this.Handle, "ptr", dest, "astr", str, "uptr", StrPut(str, "cp0"), "ptr", 0) throw OSError() } else { buf := Buffer(StrPut(str, encoding)) StrPut(str, buf, encoding) if !DllCall("WriteProcessMemory", "ptr", this.Handle, "ptr", dest, "ptr", buf, "uptr", buf.Size, "ptr", 0) throw OSError() } } WriteWString(dest, str) { if !DllCall("WriteProcessMemory", "ptr", this.Handle, "ptr", dest, "wstr", str, "uptr", StrPut(str, "utf-16"), "ptr", 0) throw OSError() } TracePointer(baseAddress, offsetArray*) { if offsetArray.Length !== 0 lastOffset := offsetArray.Pop() ptrType := this.IsWow64 ? "uint" : "ptr" pointer := this.ReadNumber(baseAddress, ptrType) for , offset in offsetArray pointer := this.ReadNumber(pointer + offset, ptrType) return pointer + lastOffset } GetModuleAddressByName(moduleName) { if !moduleEntry := ToolHelpFindModuleByName(moduleName, this.ProcessId) throw OSError(18) return moduleEntry.modBaseAddr } GetSectionAddressByName(moduleName, sectionName) { moduleEntry := ToolHelpFindModuleByName(moduleName, this.ProcessId) fileBuffer := FileRead(moduleEntry.szExePath, "RAW") pNtHeaders := fileBuffer.Ptr + NumGet(fileBuffer, 60, "int") pFileHearder := pNtHeaders + 4 pOptionalHearder := pFileHearder + 20 pSectionHeader := pOptionalHearder + NumGet(pFileHearder, 16, "ushort") loop NumGet(pFileHearder, 2, "ushort") { if StrGet(pSectionHeader + (A_Index - 1) * 40, 8, "cp0") = sectionName return moduleEntry.modBaseAddr + NumGet(pSectionHeader, (A_Index - 1) * 40 + 12, "uint") } throw Error("Unable to find the address") } GetFunctionAddressByName(moduleName, functionName) { moduleEntry := ToolHelpFindModuleByName(moduleName, this.ProcessId) fileBuffer := FileRead(moduleEntry.szExePath, "RAW") pNtHeaders := fileBuffer.Ptr + NumGet(fileBuffer, 60, "int") pFileHearder := pNtHeaders + 4 pOptionalHearder := pFileHearder + 20 sizeOfOptionalHearder := NumGet(pFileHearder, 16, "ushort") pSectionHeader := pOptionalHearder + sizeOfOptionalHearder if NumGet(pOptionalHearder, this.IsWow64 ? 96 : 112, "uint") == 0 { throw Error("Unable to find the address") } pExportDirectory := fileBuffer.Ptr + RvaToFoa(NumGet(pOptionalHearder, this.IsWow64 ? 96 : 112, "uint")) pFunctionNames := fileBuffer.Ptr + RvaToFoa(NumGet(pExportDirectory, 32, "uint")) loop NumGet(pExportDirectory, 24, "uint") { if StrGet(fileBuffer.Ptr + RvaToFoa(NumGet(pFunctionNames, (A_Index - 1) * 4, "uint")), "cp0") = functionName { pFunctionAddresses := fileBuffer.Ptr + RvaToFoa(NumGet(pExportDirectory, 28, "uint")) pNameOrdinals := fileBuffer.Ptr + RvaToFoa(NumGet(pExportDirectory, 36, "uint")) return moduleEntry.modBaseAddr + NumGet(pFunctionAddresses, NumGet(pNameOrdinals, (A_Index - 1) * 2, "ushort") * 4, "uint") } } throw Error("Unable to find the address") RvaToFoa(rva){ if rva < NumGet(pOptionalHearder, 60, "uint") return rva loop NumGet(pFileHearder, 2, "ushort") { virtualAddress := NumGet(pSectionHeader, (A_Index - 1) * 40 + 12, "uint") if rva >= virtualAddress && rva < virtualAddress + NumGet(pSectionHeader, (A_Index - 1) * 40 + 8, "uint") { return rva - virtualAddress + NumGet(pSectionHeader, (A_Index - 1) * 40 + 20, "uint") } } throw Error("Unable to find the address") } } GetThreadStackAddress(threadNumber) { for threadEntry in ToolHelpEnumThread() { if threadEntry.th32OwnerProcessID == this.ProcessId && threadNumber-- == 0 { kernel32ModuleEntry := ToolHelpFindModuleByName("kernel32.dll", this.ProcessId) if !hThread := DllCall("OpenThread", "uint", 0x1f03ff, "int", 0, "uint", threadEntry.th32ThreadID, "ptr") throw Error("Unable to find the address") DllCall("Ntdll\NtQueryInformationThread", "ptr", hThread, "uint", 0, "ptr", threadInfo := Buffer(48), "uint", threadInfo.Size, "uint*", 0) DllCall("CloseHandle", "ptr", hThread) pTeb := NumGet(threadInfo, 8, "ptr") stackBase := ptrType := ptrSize := unset if this.IsWow64 { stackBase := this.ReadNumber(pTeb + 4096 * 2 + 4, "uint") ptrType := "uint" ptrSize := 4 } else { stackBase := this.ReadNumber(pTeb + 8, "uint64") ptrType := "uint64" ptrSize := 8 } stackBuf := this.ReadBuffer(stackBase - 4096, 4096) ; find the stack entry pointing to the function that calls "ExitXXXXXThread" offsetToExitThread := 4096 - ptrSize while (offsetToExitThread >= 0) { pExitThread := NumGet(stackBuf, offsetToExitThread, ptrType) if pExitThread >= kernel32ModuleEntry.modBaseAddr && pExitThread <= kernel32ModuleEntry.modBaseAddr + kernel32ModuleEntry.modBaseSize return stackBase - 4096 + offsetToExitThread offsetToExitThread -= ptrSize } throw Error("Unable to find the address") } } throw Error("Unable to find the address") } ReadCommandLine() { if DllCall("Ntdll\NtQueryInformationProcess", "ptr", this.Handle, "uint", 0, "ptr", processBasicInfo := Buffer(48), "uint", processBasicInfo.Size, "uint*", 0) throw Error("NtQueryInformationProcess failed") pPeb := NumGet(processBasicInfo, 8, "ptr") if this.IsWow64 { pProcessParams := this.ReadNumber(pPeb + 4096 + 16, "uint") pCommandLineUnicodeString := this.ReadBuffer(pProcessParams + 64, 8) commandLine := this.ReadBuffer(NumGet(pCommandLineUnicodeString, 4, "uint"), NumGet(pCommandLineUnicodeString, "ushort")) } else { pProcessParams := this.ReadNumber(pPeb + 32, "ptr") pCommandLineUnicodeString := this.ReadBuffer(pProcessParams + 112, 16) commandLine := this.ReadBuffer(NumGet(pCommandLineUnicodeString, 8, "ptr"), NumGet(pCommandLineUnicodeString, "ushort")) } return StrGet(commandLine, "utf-16") } }
ToolHelp.ahk
ToolHelpFindProcessByName(name) { if !snapshot := DllCall("CreateToolhelp32Snapshot", "uint", 0x2, "uint", 0, "ptr") return entry := PROCESSENTRY32W() res := DllCall("Process32FirstW", "ptr", snapshot, "ptr", entry) while res { if entry.szExeFile = name { res := entry break } res := DllCall("Process32NextW", "ptr", snapshot, "ptr", entry) } DllCall("CloseHandle", "ptr", snapshot) return res } ToolHelpFindModuleByName(moduleName, pid := 0) { if !snapshot := DllCall("CreateToolhelp32Snapshot", "uint", 0x18, "uint", pid, "ptr") return entry := MODULEENTRY32W() res := DllCall("Module32FirstW", "ptr", snapshot, "ptr", entry) while res { if entry.szModule = moduleName { res := entry break } res := DllCall("Module32NextW", "ptr", snapshot, "ptr", entry) } DllCall("CloseHandle", "ptr", snapshot) return res } ToolHelpEnumProcess() { snapshot := DllCall("CreateToolhelp32Snapshot", "uint", 0x2, "uint", 0, "ptr") _processEntry := PROCESSENTRY32W() enum.__Delete := (_) => DllCall("CloseHandle", "ptr", snapshot) return enum(&processEntry) => DllCall(A_Index == 1 ? "Process32FirstW" : "Process32NextW", "ptr", snapshot, "ptr", processEntry := _processEntry) } ToolHelpEnumModule(pid := 0) { snapshot := DllCall("CreateToolhelp32Snapshot", "uint", 0x18, "uint", pid, "ptr") _moduleEntry := MODULEENTRY32W() enum.__Delete := (_) => DllCall("CloseHandle", "ptr", snapshot) return enum(&moduleEntry) => DllCall(A_Index == 1 ? "Module32FirstW" : "Module32NextW", "ptr", snapshot, "ptr", moduleEntry := _moduleEntry) } ToolHelpEnumThread() { snapshot := DllCall("CreateToolhelp32Snapshot", "uint", 0x4, "uint", 0, "ptr") _threadEntry := THREADENTRY32() enum.__Delete := (_) => DllCall("CloseHandle", "ptr", snapshot) return enum(&threadEntry) => DllCall(A_Index == 1 ? "Thread32First" : "Thread32Next", "ptr", snapshot, "ptr", threadEntry := _threadEntry) } class PROCESSENTRY32W { __New() { this.Buffer := Buffer(568) this.Ptr := this.Buffer.Ptr this.Size := this.Buffer.Size NumPut("uint", this.Size, this, 0) } cntUsage => NumGet(this, 4, "uint") th32ProcessID => NumGet(this, 8, "uint") th32DefaultHeapID => NumGet(this, 16, "uptr") th32ModuleID => NumGet(this, 24, "uint") cntThreads => NumGet(this, 28, "uint") th32ParentProcessID => NumGet(this, 32, "uint") pcPriClassBase => NumGet(this, 36, "int") dwFlags => NumGet(this, 40, "uint") szExeFile => StrGet(this.Ptr + 44) } class MODULEENTRY32W { __New() { this.Buffer := Buffer(1080) this.Ptr := this.Buffer.Ptr this.Size := this.Buffer.Size NumPut("uint", this.Size, this, 0) } th32ModuleID => NumGet(this, 4, "uint") th32ProcessID => NumGet(this, 8, "uint") GlblcntUsage => NumGet(this, 12, "uint") ProccntUsage => NumGet(this, 16, "uint") modBaseAddr => NumGet(this, 24, "ptr") modBaseSize => NumGet(this, 32, "uint") hModule => NumGet(this, 40, "ptr") szModule => StrGet(this.Ptr + 48) szExePath => StrGet(this.Ptr + 560) } class THREADENTRY32 { __New() { this.Buffer := Buffer(28) this.Ptr := this.Buffer.Ptr this.Size := this.Buffer.Size NumPut("uint", this.Size, this, 0) } th32ThreadID => NumGet(this, 8, "uint") th32OwnerProcessID => NumGet(this, 12, "uint") tpBasePri => NumGet(this, 16, "uint") }
声明:站内资源为整理优化好的代码上传分享与学习研究,如果是开源代码基本都会标明出处,方便大家扩展学习路径。请不要恶意搬运,破坏站长辛苦整理维护的劳动成果。本站为爱好者分享站点,所有内容不作为商业行为。如若本站上传内容侵犯了原著者的合法权益,请联系我们进行删除下架。
评论(0)