- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
我有一个程序可以写入我正在试验的游戏的内存。当我使用常规静态地址时,代码对我来说很好,但由于某种原因,一旦找到工作指针,我似乎就无法做到这一点。例如,我在指针扫描几次后在 Cheat Engine 中发现了这个:
每次我加载游戏并编辑值时,这个地址都会起作用。问题是我不明白如何在我的程序中使用它。这是我声明的变量,我试图插入这些值:
bool UnlimitedAmmo = false;
string AmmoPointer = "031B7324"; // <--- The address
int[] AmmoOffset = { 0x2c, 0x1e8, 0x3c8, 0x6d4, 0x508 }; // <--- It's pointers
int AmmoToFill = 1337; // <--- The Amount of ammo to give
我将这些变量传递如下:
MyMemory.ReadProcess = MyProcess[0];
MyMemory.Open();
int PointerAddress = HexToDec(AmmoPointer);
int[] PointerOffest = AmmoOffset;
int BytesWritten;
byte[] ValueToWrite = BitConverter.GetBytes(AmmoToFill);
string WrittenAddress = MyMemory.PointerWrite((IntPtr)PointerAddress, ValueToWrite,
PointerOffest, out BytesWritten);
MyMemory.CloseHandle();
我曾经使用过一个静态地址(用于不同的游戏),一旦我插入地址和偏移量,我的代码就可以正常工作。这次我难住了。任何帮助和解释将不胜感激。提前致谢。
最佳答案
我想我会在未来为人们发布一个解决方案。
如果您不想深入了解保存在那里的 C++ 代码并用 C# 重写,您可以使用一种方法来简单地使用 github 上的这个程序:
https://github.com/makemek/cheatengine-threadstack-finder
直接下载链接在这里:
https://github.com/makemek/cheatengine-threadstack-finder/files/685703/threadstack.zip
你可以给这个可执行文件传递一个进程ID并解析出你需要的线程地址。
基本上,我所做的是我的进程运行 exe,重定向输出并解析它。
然后流程结束,我们做我们需要做的事情 - 我有点觉得我在作弊,但它确实有效。
threadstack.exe
的输出通常看起来像这样:
PID 6540 (0x198c)
Grabbing handle
Success
PID: 6540 Thread ID: 0x1990
PID: 6540 Thread ID: 0x1b1c
PID: 6540 Thread ID: 0x1bbc
TID: 0x1990 = THREADSTACK 0 BASE ADDRESS: 0xbcff8c
TID: 0x1b1c = THREADSTACK 1 BASE ADDRESS: 0x4d8ff8c
TID: 0x1bbc = THREADSTACK 2 BASE ADDRESS: 0x518ff8c
这是我最终用来获取所需地址的代码:
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, [Out] byte[] lpBuffer, int dwSize, out int lpNumberOfBytesRead);
////////////////////////////////////////////////////////////////////
// These are used to find the StardewValley.Farmer structure //
//////////////////////////////////////////////////////////////////
private IntPtr Thread0Address;
private IntPtr FarmerStartAddress;
private static int[] FARMER_OFFSETS = { 0x4, 0x478, 0x218, 0x24C };
private static int FARMER_FIRST = 0x264;
//////////////////////////////////////////////////////////////////
private async void hookAll()
{
SVProcess = Process.GetProcessesByName("Stardew Valley")[0];
SVHandle = OpenProcess(ProcessAccessFlags.All, true, SVProcess.Id);
SVBaseAddress = SVProcess.MainModule.BaseAddress;
Thread0Address = (IntPtr) await getThread0Address();
getFarmerStartAddress();
}
private Task<int> getThread0Address()
{
var proc = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = "threadstack.exe",
Arguments = SVProcess.Id + "",
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = true
}
};
proc.Start();
while (!proc.StandardOutput.EndOfStream)
{
string line = proc.StandardOutput.ReadLine();
if (line.Contains("THREADSTACK 0 BASE ADDRESS: "))
{
line = line.Substring(line.LastIndexOf(":") + 2);
return Task.FromResult(int.Parse(line.Substring(2), System.Globalization.NumberStyles.HexNumber));
}
}
return Task.FromResult(0);
}
private void getFarmerStartAddress()
{
IntPtr curAdd = (IntPtr) ReadInt32(Thread0Address - FARMER_FIRST);
foreach (int x in FARMER_OFFSETS)
curAdd = (IntPtr) ReadInt32(curAdd + x);
FarmerStartAddress = (IntPtr) curAdd;
}
private int ReadInt32(IntPtr addr)
{
byte[] results = new byte[4];
int read = 0;
ReadProcessMemory(SVHandle, addr, results, results.Length, out read);
return BitConverter.ToInt32(results, 0);
}
如果您有兴趣更新 C++ 代码,我相信相关部分在这里。
它实际上看起来并不太复杂——我认为你只是在获取 kernal32.dll
的基地址。并通过检查它是否为 >=
在线程堆栈中查找该地址到基地址或<=
到base address + size
在读取每 4 个字节时 - 我不得不玩它。
DWORD GetThreadStartAddress(HANDLE processHandle, HANDLE hThread) {
/* rewritten from https://github.com/cheat-engine/cheat-engine/blob/master/Cheat%20Engine/CEFuncProc.pas#L3080 */
DWORD used = 0, ret = 0;
DWORD stacktop = 0, result = 0;
MODULEINFO mi;
GetModuleInformation(processHandle, GetModuleHandle("kernel32.dll"), &mi, sizeof(mi));
stacktop = (DWORD)GetThreadStackTopAddress_x86(processHandle, hThread);
/* The stub below has the same result as calling GetThreadStackTopAddress_x86()
change line 54 in ntinfo.cpp to return tbi.TebBaseAddress
Then use this stub
*/
//LPCVOID tebBaseAddress = GetThreadStackTopAddress_x86(processHandle, hThread);
//if (tebBaseAddress)
// ReadProcessMemory(processHandle, (LPCVOID)((DWORD)tebBaseAddress + 4), &stacktop, 4, NULL);
CloseHandle(hThread);
if (stacktop) {
//find the stack entry pointing to the function that calls "ExitXXXXXThread"
//Fun thing to note: It's the first entry that points to a address in kernel32
DWORD* buf32 = new DWORD[4096];
if (ReadProcessMemory(processHandle, (LPCVOID)(stacktop - 4096), buf32, 4096, NULL)) {
for (int i = 4096 / 4 - 1; i >= 0; --i) {
if (buf32[i] >= (DWORD)mi.lpBaseOfDll && buf32[i] <= (DWORD)mi.lpBaseOfDll + mi.SizeOfImage) {
result = stacktop - 4096 + i * 4;
break;
}
}
}
delete buf32;
}
return result;
}
您可以像这样在 C# 中获取线程基地址:
https://stackoverflow.com/a/8737521/1274820
关键是调用 NtQueryInformationThread
功能。这不是一个完全“官方”的函数(过去可能没有记录?),但文档建议没有其他方法可以获取线程的起始地址。
我已经将它封装成一个对 .NET 友好的调用,它接受一个线程 ID 并将起始地址返回为 IntPtr
.此代码已在 x86 和 x64 模式下测试过,后者在 32 位和 64 位目标进程上都进行了测试。
我没有测试的一件事是以低权限运行它;我希望此代码要求调用者拥有 SeDebugPrivilege
.
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
class Program
{
static void Main(string[] args)
{
PrintProcessThreads(Process.GetCurrentProcess().Id);
PrintProcessThreads(4156); // some other random process on my system
Console.WriteLine("Press Enter to exit.");
Console.ReadLine();
}
static void PrintProcessThreads(int processId)
{
Console.WriteLine(string.Format("Process Id: {0:X4}", processId));
var threads = Process.GetProcessById(processId).Threads.OfType<ProcessThread>();
foreach (var pt in threads)
Console.WriteLine(" Thread Id: {0:X4}, Start Address: {1:X16}",
pt.Id, (ulong) GetThreadStartAddress(pt.Id));
}
static IntPtr GetThreadStartAddress(int threadId)
{
var hThread = OpenThread(ThreadAccess.QueryInformation, false, threadId);
if (hThread == IntPtr.Zero)
throw new Win32Exception();
var buf = Marshal.AllocHGlobal(IntPtr.Size);
try
{
var result = NtQueryInformationThread(hThread,
ThreadInfoClass.ThreadQuerySetWin32StartAddress,
buf, IntPtr.Size, IntPtr.Zero);
if (result != 0)
throw new Win32Exception(string.Format("NtQueryInformationThread failed; NTSTATUS = {0:X8}", result));
return Marshal.ReadIntPtr(buf);
}
finally
{
CloseHandle(hThread);
Marshal.FreeHGlobal(buf);
}
}
[DllImport("ntdll.dll", SetLastError = true)]
static extern int NtQueryInformationThread(
IntPtr threadHandle,
ThreadInfoClass threadInformationClass,
IntPtr threadInformation,
int threadInformationLength,
IntPtr returnLengthPtr);
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr OpenThread(ThreadAccess dwDesiredAccess, bool bInheritHandle, int dwThreadId);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool CloseHandle(IntPtr hObject);
[Flags]
public enum ThreadAccess : int
{
Terminate = 0x0001,
SuspendResume = 0x0002,
GetContext = 0x0008,
SetContext = 0x0010,
SetInformation = 0x0020,
QueryInformation = 0x0040,
SetThreadToken = 0x0080,
Impersonate = 0x0100,
DirectImpersonation = 0x0200
}
public enum ThreadInfoClass : int
{
ThreadQuerySetWin32StartAddress = 9
}
}
我的系统上的输出:
Process Id: 2168 (this is a 64-bit process)
Thread Id: 1C80, Start Address: 0000000001090000
Thread Id: 210C, Start Address: 000007FEEE8806D4
Thread Id: 24BC, Start Address: 000007FEEE80A74C
Thread Id: 12F4, Start Address: 0000000076D2AEC0
Process Id: 103C (this is a 32-bit process)
Thread Id: 2510, Start Address: 0000000000FEA253
Thread Id: 0A0C, Start Address: 0000000076F341F3
Thread Id: 2438, Start Address: 0000000076F36679
Thread Id: 2514, Start Address: 0000000000F96CFD
Thread Id: 2694, Start Address: 00000000025CCCE6
除了括号中的内容,因为这需要额外的 P/Invoke。
关于SymFromAddress
“找不到模块”错误,我只想提一下,需要调用 SymInitialize
与 fInvadeProcess = true
或手动加载模块,as documented on MSDN .
关于c# - 使用 C# Cheat Engine 中的指针,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28620186/
我的一个 friend 提示说,SQL managment studio express 被他的系统管理员设置的一些安全设置禁止了。我推荐使用 OSQL 我的问题是 我需要一些基本命令,例如附加、分离
在 NLP 中,有一个 Gazetteer 的概念,它对于创建注释非常有用。据我了解, 地名词典由一组列表组成,其中包含城市、组织、星期几等实体名称。这些列表用于查找这些名称在文本中的出现情况,例如用
我正在尝试分析一些方法以查看哪些实现速度更快。我遇到了一个障碍,因为 java 似乎在每次请求时都不处理所有信息来欺骗配置文件。 public void Profile() { double[
关闭。这个问题需要更多focused .它目前不接受答案。 想改进这个问题吗? 更新问题,使其只关注一个问题 editing this post . 关闭 5 个月前。 Improve this q
如果您正在编写游戏,您应该考虑作弊者以及如何防止他们作弊。 我认为不仅是 MMO 多人游戏,还包括单人游戏或“自制”p2p mp 游戏。 当游戏完全基于服务器-客户端架构时,我认为工作几乎完成,但也存
我找到了一个内存地址并使用 Cheat Engine 的指针扫描来获取引用指针。要在脚本中使用它,我需要一个基址,即 [game.exe+009274]。如何将其转换为在 AutoIt 脚本中使用的地
我几个月前开始编程。我正在 Animate CC 中制作一个完整的客户端游戏,因此我正在尝试一种针对内存扫描软件的简单措施。 我试图避免人们改变我的 money 变量。 var canMoneyCha
我怎样才能把我的按钮放在中间而不用任何类型的“margin cheat”(例如设置 margin-left: 525px;)? HTML H1 tag Pr
如何在不设置 padding 的情况下将我的 h1 标签置于 banner 的 middle 中心? HTML Group Title CSS .banner
我正在制作一个将分数发送到服务器的 C++11 游戏。我将分数存储为一个简单的 float ,因此人们使用像 Cheat Engine 这样的软件可以在将分数发送到服务器之前轻松更改分数的值。 如何保
是否可以避免在 Cheat Engine 中搜索值并设置它们(我在下面解释过,我需要什么)?我知道你可以找到地址指针并创建培训师,但问题是我使用 Cheat Engine 的应用程序被我的公司更新了很
我又回来了,沮丧并拼命寻求帮助:D。 我正在尝试为一个简单的程序创建一个作弊程序,它基本上是一个 .dll 文件,当它使用基地址注入(inject)主程序时,它将更改主程序中的整数值。问题是,我无法使
询问后this question (C++: Can I get out of the bounds of my app’s memory with a pointer?) , 我决定接受无法使用指针
关于计划 我有一个程序可以写入我正在试验的游戏的内存。当我使用常规静态地址时,代码对我来说很好,但由于某种原因,一旦找到工作指针,我似乎就无法做到这一点。例如,我在指针扫描几次后在 Cheat Eng
简而言之,如何在 Linux 中搜索、查看和修改内存中的值,最好尽可能轻松/简单。 Like this . 最佳答案 最接近的是 scanmem sudo apt-get install scanme
我有一个程序,在那个程序中有一些变量(用户名和“特权级别”)只有在用户登录时才会改变。有没有办法在程序运行时“保护”这些变量免受内存编辑等的影响,但如果用户使用其他用户名登录,程序仍然能够更改它们。
我正在编写一个策划游戏,这是我的代码: import java.util.*; public class mm { public static void main(String[] args)
我一直在通过深入研究一个项目(一个简单的 2d 游戏)来学习 C++。我试图实现一组作弊,但我在字符串操作方面是个新手。我确信会有比下面的代码更优雅的方式来实现我想要的。 根据要求,stringBuf
我想使用像 text-indent:-9999em 或负边距这样的技术来用更漂亮的图片替换我的文本,但我想知道搜索引擎是否会将此视为一种作弊? 我想它要知道这一点,它必须读取我的 CSS 文件,所以我
我最近学习了如何使用 Cheat Engine 查找进程的基地址。我在 Windows XP 上用 Solitaire 做到了这一点,我找到了分数的基地址(类似于 000AABBC)并且该地址从未改变
我是一名优秀的程序员,十分优秀!